# Flowmason FM Docs (All-in-One)


---

## README.md

# FlowMason Documentation

Welcome to FlowMason - an AI pipeline orchestration platform for building, debugging, and deploying intelligent workflows.

## The FlowMason Platform

FlowMason uses a **Salesforce DX-style hybrid model**:

```
LOCAL DEVELOPMENT                    STAGING/PRODUCTION
┌─────────────────────┐             ┌─────────────────────┐
│ .pipeline.json      │  deploy     │ PostgreSQL Database │
│ files (Git repo)    │────────────>│ Backend APIs        │
│ VSCode + Extension  │             │ Runtime Execution   │
└─────────────────────┘             └─────────────────────┘
        │                                    │
   Fast iteration                    Production runtime
   Version control                   API consumption
   Debug & test                      Full observability
```

- **Development**: File-based pipelines (`.pipeline.json`) in VSCode with Git version control
- **Deployment**: Push to staging/production orgs where pipelines run from databases
- **Runtime**: Backend APIs expose pipelines for consumption

See [The Hybrid Model](01-vision/hybrid-model.md) for details.

## Quick Links

| I want to... | Go to |
|--------------|-------|
| **Follow step-by-step tutorials** | [Tutorials](tutorials/README.md) |
| **Check implementation status** | [Implementation Status](00-status/implementation-status.md) |
| Understand the platform model | [Hybrid Model](01-vision/hybrid-model.md) |
| Get started quickly | [Getting Started](02-getting-started/quickstart.md) |
| Understand the concepts | [Concepts](03-concepts/architecture-overview.md) |
| Build a node | [Building Nodes](04-core-framework/decorators/node.md) |
| Build an operator | [Building Operators](04-core-framework/decorators/operator.md) |
| Use control flow | [Control Flow](03-concepts/control-flow.md) |
| Debug a pipeline | [Debugging](09-debugging-testing/debugging/current-debugging.md) |
| Use the VSCode extension | [VSCode Extension](07-vscode-extension/overview.md) |
| Deploy to staging/production | [Deployment](08-packaging-deployment/deploying-packages.md) |
| Understand the architecture | [Architecture](10-architecture/system-overview.md) |

## Tutorials

New to FlowMason? Start here:

| Tutorial | Duration | Description |
|----------|----------|-------------|
| [1. Getting Started](tutorials/01-getting-started.md) | 15 min | Install and set up FlowMason |
| [2. Building Your First Pipeline](tutorials/02-building-first-pipeline.md) | 30 min | Create a 3-stage AI pipeline |
| [3. Debugging Pipelines](tutorials/03-debugging-pipelines.md) | 25 min | Breakpoints, stepping, prompt editing |
| [4. Testing Pipelines](tutorials/04-testing-pipelines.md) | 25 min | Write tests, mocks, coverage |
| [5. Working with Components](tutorials/05-working-with-components.md) | 35 min | Create custom nodes and operators |

## Documentation Structure

```
fmdocs/
├── 00-status/          # Implementation status and remaining work
├── tutorials/          # Step-by-step tutorials (start here!)
├── 01-vision/          # Platform vision, hybrid model, roadmap
├── 02-getting-started/ # Installation and first steps
├── 03-concepts/        # Core concepts explained
├── 04-core-framework/  # Decorators, types, execution engine
├── 05-components/      # Built-in component reference
├── 06-studio/          # Studio backend and frontend
├── 07-vscode-extension/# VSCode extension features
├── 08-packaging-deployment/ # Packages, deployment, CI/CD
├── 09-debugging-testing/    # Debug and test pipelines
├── 10-architecture/    # System architecture deep dive
└── 11-contributing/    # How to contribute
```

## What is FlowMason?

FlowMason is a framework for building AI-powered pipelines that:

- **Compose** - Connect nodes (LLM calls, operators, sub-pipelines) into workflows
- **Execute** - Run pipelines with full observability and control
- **Debug** - Step through execution, inspect data, iterate on prompts
- **Deploy** - Push pipelines to staging/production environments
- **Test** - Unit test nodes, integration test pipelines
- **Version** - Git-friendly file format for collaboration

## Environments

| Environment | Storage | Execution | Use Case |
|-------------|---------|-----------|----------|
| **Local (File Mode)** | `.pipeline.json` files | Direct from files | Fast development |
| **Local (Org Mode)** | SQLite | From local DB | Test DB behavior |
| **Staging Org** | PostgreSQL | From DB via API | Integration testing |
| **Production Org** | PostgreSQL | From DB via API | Live runtime |

## Component Types

FlowMason has three types of components:

| Type | Decorator | Purpose | Example |
|------|-----------|---------|---------|
| **Node** | `@node` | AI-powered operations requiring LLM | Text generation, summarization |
| **Operator** | `@operator` | Deterministic data transformations | JSON parsing, filtering, HTTP calls |
| **Control Flow** | `@control_flow` | Pipeline execution control | Conditionals, loops, error handling |

## Current Status (December 2025)

### Core Framework
- 3 decorators: `@node`, `@operator`, `@control_flow`
- 18 built-in components (6 control flow, 7 operators, 5 nodes)
- UniversalExecutor with timeout, retry, and cancellation support
- DAGExecutor for pipeline execution with control flow handling

### CLI (Fully Implemented)
```bash
fm run              # Execute pipeline from file
fm validate         # Validate pipeline files
fm init             # Initialize new FlowMason project
fm deploy           # Deploy pipelines to org
fm pull             # Pull pipelines from org
fm pack             # Build .fmpkg package
fm install          # Install .fmpkg package
fm studio           # start/stop/status/restart
fm org              # login/logout/list/default/display
```

### Studio Backend
- FastAPI backend with REST API and WebSocket support
- Pipeline management, execution, and debugging endpoints
- Real-time execution updates via WebSocket
- Test execution endpoint (`/api/v1/tests/run`)

### VSCode Extension (v0.4.0)
**Language Features:**
- IntelliSense for decorators and component patterns
- Diagnostics for FlowMason validation
- Hover documentation
- CodeLens (Run/Preview buttons)
- Go to Definition / Find References
- Document symbols for Outline view

**Pipeline Editing:**
- DAG Canvas custom editor for visual pipeline editing
- Pipeline stages tree view
- Stage configuration panel
- Native Outline integration for pipeline structure

**Debugging (DAP):**
- Full Debug Adapter Protocol integration
- Breakpoints on pipeline stages (F9)
- Step through execution (F10)
- Variables panel with stage inputs/outputs
- Debug configurations in launch.json

**Prompt Iteration:**
- Prompt Editor sidebar panel during debug
- View and edit system/user prompts
- Re-run individual stages with modified prompts
- Prompt version history
- Side-by-side output comparison

**Test Explorer:**
- VSCode Test Explorer integration
- `.test.json` test file format
- Comprehensive assertion types
- Pipeline and component testing
- Test discovery and execution

**Studio Management:**
- Start/Stop/Restart Studio from VSCode
- Status bar with Studio connection status
- Component preview and testing

### Package System
- `.fmpkg` package format (ZIP with manifest)
- Package building, installation, and deployment
- Dependency resolution

See [Product Vision](01-vision/product-vision.md) for the complete roadmap.

## Installation

```bash
# Install FlowMason core
pip install flowmason-core

# Install FlowMason Studio
pip install flowmason-studio

# Install VSCode extension
code --install-extension flowmason.flowmason
```

## CLI Commands (Preview)

```bash
# Org management
flowmason org:login --alias staging --instance-url https://staging.flowmason.com
flowmason org:list

# Deploy pipelines
flowmason deploy --target staging
flowmason deploy --target production

# Pull from org
flowmason pull --target production

# Local execution
flowmason run pipelines/main.pipeline.json
flowmason run pipelines/main.pipeline.json --debug
```

## Next Steps

1. [Hybrid Model](01-vision/hybrid-model.md) - Understand the platform architecture
2. [Quick Start Guide](02-getting-started/quickstart.md) - Build your first pipeline
3. [Core Concepts](03-concepts/architecture-overview.md) - Understand how FlowMason works
4. [Component Reference](05-components/) - Explore built-in components


---

## 00-status/future-features.md

# FlowMason Product Roadmap

The definitive roadmap for FlowMason's evolution from a pipeline execution framework to an AI-native workflow platform.

---

## Executive Summary

FlowMason is positioned to become the **AI-native workflow platform** that bridges the gap between visual pipeline design, enterprise integration, and modern AI capabilities. This roadmap outlines 24 major features organized into four priority stages, with quick wins first.

### Vision

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                         FlowMason Platform Vision                           │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│   ┌─────────────┐     ┌─────────────┐     ┌─────────────┐                  │
│   │   Design    │     │   Execute   │     │   Deploy    │                  │
│   │             │     │             │     │             │                  │
│   │ • VSCode    │────▶│ • Studio    │────▶│ • Docker    │                  │
│   │ • Visual    │     │ • Debug     │     │ • SDK       │                  │
│   │ • AI-Assist │     │ • Monitor   │     │ • Code Gen  │                  │
│   └─────────────┘     └─────────────┘     └─────────────┘                  │
│          │                   │                   │                          │
│          └───────────────────┴───────────────────┘                          │
│                              │                                              │
│                    ┌─────────▼─────────┐                                   │
│                    │   MCP Protocol    │                                   │
│                    │   (AI-Native)     │                                   │
│                    └───────────────────┘                                   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## Roadmap Stages

### 🚀 Stage 1: Quick Wins (P1)
**Timeline Focus: Immediate**

Low effort, high impact features that provide immediate value.

| Feature | Effort | Status |
|---------|--------|--------|
| Docker - Local Dev | Low | ✅ DONE |
| Execution Endpoint Auth | Low | ✅ DONE |
| Local .fmpkg Import | Low | ✅ DONE |
| AI Pipeline Generation (Docs) | Low | ✅ DONE |
| Component Visual - Icons & Colors | Low | ✅ DONE |
| MCP Server (Core) | Medium | ✅ DONE |
| Secrets Management (Basic) | Medium | ✅ DONE |

**Quick Win Themes:**
- 🐳 **Docker**: Single-command local development
- 🔐 **Security**: Token auth for API endpoints
- 📦 **Packaging**: Import pipeline packages
- 🤖 **AI-Ready**: PIPELINES.md for AI generation
- 🎨 **Visual Polish**: Icons and colors for components

---

### ⚡ Stage 2: Core Platform (P2)
**Timeline Focus: Near-term**

Essential features that form the production-ready platform.

#### Deployment & Operations
| Feature | Effort | Status |
|---------|--------|--------|
| Docker - Staging | Medium | ✅ DONE |
| Docker - Production | Medium | ✅ DONE |
| Web Portal - Operations Dashboard | Medium | |
| Web Portal - API Console | Medium | |
| Web Portal - Admin Panel | Medium | |

#### Developer Experience
| Feature | Effort |
|---------|--------|
| Visual Field Mapping (Basic) | Medium |
| Visual Field Mapping (Schema Inference) | Medium |
| Visual Field Mapping (Validation) | Low |
| Component Visual - Shapes & Ports | Medium |
| Pipeline Debugger (Basic) | Medium |

#### AI & Automation
| Feature | Effort | Status |
|---------|--------|--------|
| MCP Client Operators | Medium | ✅ DONE |
| AI Generation - Interactive | Medium | |
| LLM Cost Tracking | Medium | ✅ DONE |
| Prompt Library | Medium | |

#### Pipeline Lifecycle
| Feature | Effort | Status |
|---------|--------|--------|
| Pipeline Versioning | Medium | |
| Pipeline Testing - Basic Runner | Medium | |
| Scheduling - Cron | Medium | |
| Webhook Triggers | Medium | ✅ DONE |

#### SDK & Integration
| Feature | Effort |
|---------|--------|
| Embedded SDK (Python) | Medium |
| Code Gen - Python | High |
| Code Gen - Node.js/TypeScript | High |
| OAuth 2.0 Support | Medium |
| Built-in Template Gallery | Medium |

---

### 🎯 Stage 3: Advanced Features (P3)
**Timeline Focus: Mid-term**

Sophisticated capabilities for enterprise and power users.

#### Enterprise & Scale
| Feature | Effort |
|---------|--------|
| Remote Registry | High |
| Pipeline-Level Permissions | High |
| Multi-Region Deployment | Very High |
| Secrets - Rotation & Audit | Medium |
| OpenTelemetry Integration | Medium |

#### Advanced AI
| Feature | Effort |
|---------|--------|
| MCP Advanced (AI-assisted) | High |
| AI Generation - MCP Tool | Medium |
| Natural Language Builder | High |
| Prompt A/B Testing | High |

#### Developer Tools
| Feature | Effort |
|---------|--------|
| Debugger - Time Travel | High |
| Pipeline Testing - Mocking & Snapshots | Medium |
| Event-Driven Triggers | High |
| Real-time Collaboration | Very High |
| Execution Analytics & AI Insights | High |

#### SDKs & Integrations
| Feature | Effort |
|---------|--------|
| Embedded SDK (TypeScript) | Medium |
| Embedded SDK (React Hooks) | Low |
| VSCode Extension MCP | Medium |
| Web Portal MCP Integration | Medium |
| Code Gen - Salesforce Apex | High |
| Code Gen - Serverless (Lambda/Workers) | Medium |

#### Ecosystem
| Feature | Effort |
|---------|--------|
| Pipeline Marketplace | Very High |
| Component Visual - Rich Cards | High |

---

### 🔮 Stage 4: Future Vision (P4)
**Timeline Focus: Long-term**

Ambitious features for long-term differentiation.

| Feature | Effort |
|---------|--------|
| Code Gen - Go/Java/Rust | High |
| Kubernetes Operator | Very High |
| Visual Pipeline Diff & Merge | High |
| Pipeline Inheritance & Composition | High |

---

## Feature Categories

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                         Feature Categories                                   │
├───────────────────┬─────────────────────────────────────────────────────────┤
│ 🐳 Deployment     │ Docker, Multi-Region, Serverless                        │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 🔐 Security       │ Auth, Secrets, Permissions, OAuth                       │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 🎨 Visual Editor  │ Field Mapping, Icons, DAG Canvas, Collaboration        │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 🤖 AI-Native      │ MCP, Natural Language, Cost Tracking, Prompts          │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 📦 Packaging      │ .fmpkg Import, Registry, Marketplace                   │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 🧪 Testing        │ Debugger, Mocking, Snapshots, A/B Testing              │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 📊 Operations     │ Portal, Analytics, Scheduling, Webhooks                │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 🔌 SDKs           │ Python, TypeScript, React, Embedded                    │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 💻 Code Gen       │ Python, Node, Apex, Lambda, Go/Java/Rust               │
├───────────────────┼─────────────────────────────────────────────────────────┤
│ 📈 Versioning     │ Pipeline Versions, Rollback, Environments              │
└───────────────────┴─────────────────────────────────────────────────────────┘
```

---

## Strategic Differentiators

### 1. AI-Native (MCP Integration)
FlowMason as both **MCP Server** (expose pipelines to AI) and **MCP Client** (call AI tools from pipelines). This positions FlowMason as the workflow backbone for AI agents.

### 2. Code Generation
Unlike other workflow tools that lock you in, FlowMason can **compile pipelines to standalone code** (Python, Node, Apex). Run anywhere, no runtime dependency.

### 3. Visual Field Mapping
**Drag-and-drop data mapping** with schema inference from the component registry. Lower the barrier for non-developers while maintaining power for developers.

### 4. Developer-First
**VSCode-native** editing experience, not a browser-based alternative. The IDE is the source of truth; the web portal is for operations.

### 5. Enterprise Ready
Built-in **SAML/SSO**, multi-tenant organizations, secrets management, and audit logging from day one.

---

## Success Metrics

| Stage | Key Metrics |
|-------|-------------|
| **P1 Quick Wins** | Time to first pipeline: < 5 minutes |
| **P2 Core** | Production deployments, SDK adoption |
| **P3 Advanced** | Enterprise deals, marketplace listings |
| **P4 Vision** | Platform ecosystem, community growth |

---

## Document Structure

This document details each feature with:
- **Concept**: What and why
- **Current State**: What exists today
- **Mockups**: Visual designs (ASCII art)
- **Implementation**: Technical approach
- **Files**: Affected code paths

---

# Feature Details

Below are detailed specifications for each planned feature, organized by original feature number.

---

## 1. Pipeline Packaging & Import

Enable users to package, share, and import pipelines from within VSCode.

### Current State
- `.fmpkg` package format exists (ZIP with manifest.json)
- `PackageBuilder` can include pipelines in packages
- `PackageInstaller` installs to `~/.flowmason/packages/`
- VSCode has `buildPackage` command and packages tree view

### Planned Features

#### Phase 1: Local .fmpkg Import
- [ ] Add "Import Pipeline Package" command in VSCode
- [ ] File picker for `.fmpkg` files
- [ ] Extract pipelines to current project's `pipelines/` directory
- [ ] Handle dependencies (prompt to install missing operators)
- [ ] Show import summary dialog

#### Phase 2: Built-in Template Gallery
- [ ] Bundle common pipeline templates with extension
- [ ] Add "Pipeline Templates" sidebar section
- [ ] Categories: ETL, AI/LLM, Data Processing, Integration
- [ ] "Use Template" action creates pipeline in project
- [ ] Template preview with description and stage diagram

#### Phase 3: Remote Registry
- [ ] Central registry at flowmason.com/registry
- [ ] `fm install <package-name>` CLI command
- [ ] VSCode "Browse Registry" command
- [ ] Search by name, tags, category
- [ ] Version management and updates
- [ ] User accounts for publishing

### Package Format Enhancement
```json
{
  "name": "etl-starter-kit",
  "version": "1.0.0",
  "description": "Common ETL pipeline patterns",
  "type": "pipeline-pack",
  "pipelines": [
    "pipelines/data-validation.pipeline.json",
    "pipelines/batch-processing.pipeline.json"
  ],
  "dependencies": {
    "flowmason": ">=0.7.0"
  },
  "tags": ["etl", "data", "validation"]
}
```

---

## 2. API Authentication & Authorization

Secure access to pipelines via tokens and OAuth2.

### Current State (Already Implemented)

#### API Keys
- `APIKey` model with scopes: `FULL`, `READ`, `EXECUTE`, `DEPLOY`
- Key format: `fm_live_<48-char-hex>` with prefix for identification
- SHA-256 hashing for secure storage
- Rate limiting (configurable per key)
- Expiration and revocation support
- Full CRUD API routes at `/api/v1/auth/api-keys`

**Files:** `studio/flowmason_studio/auth/models.py`, `studio/flowmason_studio/auth/service.py`

#### Users & Organizations
- User model with password hashing (SHA-256)
- Organization model with plans and limits (users, pipelines, executions/day)
- Org memberships with roles: `OWNER`, `ADMIN`, `DEVELOPER`, `VIEWER`
- SSO fields for external identity providers

**Files:** `studio/flowmason_studio/auth/models.py`, `studio/flowmason_studio/auth/service.py`

#### Supabase JWT Integration
- JWT verification via Supabase `/auth/v1/user` endpoint
- Role-based access control middleware
- Development mode fallback (no auth required locally)
- Pre-built role dependencies: `require_admin`, `require_pipeline_developer`, `require_node_developer`

**Files:** `studio/flowmason_studio/middleware/auth.py`

#### SAML/SSO (Enterprise)
- Full SAML 2.0 Service Provider implementation
- Supported IdPs: Okta, Azure AD, Google, OneLogin, Ping, Auth0, Custom
- SP-initiated and IdP-initiated SSO flows
- Just-in-time (JIT) user provisioning
- Configurable attribute mapping
- SP metadata generation for IdP configuration

**Files:** `studio/flowmason_studio/auth/saml.py`, `studio/flowmason_studio/api/routes/saml.py`

#### Audit Logging
- `AuditLogEntry` model tracking all actions
- Captures: user_id, api_key_id, ip_address, user_agent
- Action types: `pipeline.create`, `execution.run`, `api_key.create`, etc.
- Query API with filtering by action/resource type

**Files:** `studio/flowmason_studio/auth/service.py` (lines 525-623)

### Planned Features (Not Yet Implemented)

#### Phase 1: OAuth 2.0 Support
- [ ] OAuth 2.0 Authorization Code flow for web apps
- [ ] Client Credentials flow for service-to-service
- [ ] Refresh token support with rotation
- [ ] OAuth client registration API (`/api/v1/oauth/clients`)
- [ ] Token introspection endpoint
- [ ] PKCE support for public clients

```python
# Example OAuth client registration
POST /api/v1/oauth/clients
{
  "name": "My Integration",
  "redirect_uris": ["https://myapp.com/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "scopes": ["read", "execute"]
}
```

#### Phase 2: Standalone JWT Tokens
- [ ] JWT token issuing without Supabase dependency
- [ ] Configurable signing keys (RS256/HS256)
- [ ] Token claims customization
- [ ] Short-lived access tokens + refresh tokens
- [ ] Token revocation via JTI blacklist

#### Phase 3: Pipeline-Level Permissions
- [ ] Fine-grained access control per pipeline
- [ ] Share pipelines with specific users/organizations
- [ ] Permission levels: `view`, `run`, `edit`, `admin`
- [ ] Pipeline visibility: `private`, `org`, `public`
- [ ] Access inheritance from folders

```json
{
  "pipeline_id": "pipe_abc123",
  "permissions": [
    {"principal": "user_xyz", "level": "edit"},
    {"principal": "org_acme", "level": "run"},
    {"principal": "*", "level": "view"}
  ]
}
```

#### Phase 4: Enforcement on Execution Endpoints
- [ ] Require auth on `/api/v1/debug/run` (currently open)
- [ ] Scope validation: `execute` scope required for running pipelines
- [ ] Rate limiting per API key/user
- [ ] Execution quotas per organization plan
- [ ] Webhook authentication (HMAC signatures)

### API Key Scopes Reference

| Scope | Permissions |
|-------|-------------|
| `full` | All operations |
| `read` | List/get pipelines, view executions |
| `execute` | Run pipelines, view results |
| `deploy` | Deploy pipelines to production |

---

## 3. Docker Installation & Deployment

Containerized deployment for local development, staging, and production environments.

### Current State
- No Docker support currently exists
- Manual Python installation required
- No standardized deployment process

### Planned Features

#### Phase 1: Local Development (Docker Compose)

**Single-command local setup:**
```bash
# Clone and start
git clone https://github.com/flowmason/flowmason.git
cd flowmason
docker compose up -d

# Access Studio at http://localhost:8999
```

**docker-compose.yml structure:**
```yaml
version: '3.8'

services:
  studio:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8999:8999"
    volumes:
      - ./pipelines:/app/pipelines          # Mount local pipelines
      - flowmason-data:/app/.flowmason      # Persist database
    environment:
      - FLOWMASON_ENV=development
      - FLOWMASON_LOG_LEVEL=debug
    depends_on:
      - redis

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis-data:/data

  # Optional: PostgreSQL for production-like setup
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: flowmason
      POSTGRES_USER: flowmason
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-flowmason}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    profiles:
      - production

volumes:
  flowmason-data:
  redis-data:
  postgres-data:
```

**Dockerfile:**
```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    git curl && \
    rm -rf /var/lib/apt/lists/*

# Install FlowMason
COPY pyproject.toml .
COPY core/ core/
COPY studio/ studio/
COPY lab/ lab/

RUN pip install --no-cache-dir -e .

# Build frontend
COPY studio/frontend/ studio/frontend/
WORKDIR /app/studio/frontend
RUN npm ci && npm run build

WORKDIR /app

# Create non-root user
RUN useradd -m -u 1000 flowmason
USER flowmason

EXPOSE 8999

CMD ["fm", "studio", "start", "--host", "0.0.0.0", "--port", "8999"]
```

#### Phase 2: Staging Environment

**docker-compose.staging.yml:**
```yaml
version: '3.8'

services:
  studio:
    image: flowmason/studio:${VERSION:-latest}
    ports:
      - "8999:8999"
    environment:
      - FLOWMASON_ENV=staging
      - DATABASE_URL=postgresql://flowmason:${DB_PASSWORD}@postgres:5432/flowmason
      - REDIS_URL=redis://redis:6379
      - SUPABASE_URL=${SUPABASE_URL}
      - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
    depends_on:
      - postgres
      - redis
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: flowmason
      POSTGRES_USER: flowmason
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  postgres-data:
  redis-data:
```

**Usage:**
```bash
# Create .env.staging
cp .env.example .env.staging
# Edit with staging credentials

# Deploy staging
docker compose -f docker-compose.staging.yml --env-file .env.staging up -d

# View logs
docker compose -f docker-compose.staging.yml logs -f studio

# Update to new version
docker compose -f docker-compose.staging.yml pull
docker compose -f docker-compose.staging.yml up -d
```

#### Phase 3: Production Deployment

**docker-compose.production.yml:**
```yaml
version: '3.8'

services:
  studio:
    image: flowmason/studio:${VERSION}
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '0.5'
          memory: 1G
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
    environment:
      - FLOWMASON_ENV=production
      - DATABASE_URL=postgresql://flowmason:${DB_PASSWORD}@postgres:5432/flowmason
      - REDIS_URL=redis://redis:6379
      - SUPABASE_URL=${SUPABASE_URL}
      - SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY}
      - SUPABASE_SERVICE_ROLE_KEY=${SUPABASE_SERVICE_ROLE_KEY}
      - SECRET_KEY=${SECRET_KEY}
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8999/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy

  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - studio
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: flowmason
      POSTGRES_USER: flowmason
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./backups:/backups
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U flowmason"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis-data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  postgres-data:
  redis-data:
```

**Production deployment script (deploy.sh):**
```bash
#!/bin/bash
set -e

VERSION=${1:-latest}
ENV_FILE=${2:-.env.production}

echo "Deploying FlowMason Studio v${VERSION}..."

# Pull latest images
docker compose -f docker-compose.production.yml pull

# Backup database before upgrade
docker compose -f docker-compose.production.yml exec postgres \
  pg_dump -U flowmason flowmason > backups/backup-$(date +%Y%m%d-%H%M%S).sql

# Rolling update
docker compose -f docker-compose.production.yml --env-file $ENV_FILE up -d --no-deps studio

# Wait for health check
echo "Waiting for health check..."
sleep 30
curl -f http://localhost:8999/health || exit 1

echo "Deployment complete!"
```

### Environment Variables Reference

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `FLOWMASON_ENV` | No | development | Environment: development, staging, production |
| `DATABASE_URL` | Prod | SQLite | PostgreSQL connection string |
| `REDIS_URL` | No | None | Redis connection for caching/queues |
| `SUPABASE_URL` | Prod | None | Supabase project URL |
| `SUPABASE_ANON_KEY` | Prod | None | Supabase anonymous key |
| `SUPABASE_SERVICE_ROLE_KEY` | Prod | None | Supabase service role key |
| `SECRET_KEY` | Prod | Auto | JWT signing key (generate with `openssl rand -hex 32`) |
| `FLOWMASON_LOG_LEVEL` | No | info | Logging level: debug, info, warning, error |
| `MAX_WORKERS` | No | 4 | Number of worker processes |

### Quick Start Commands

```bash
# Local development
docker compose up -d
docker compose logs -f

# Run a pipeline
docker compose exec studio fm run pipelines/my-pipeline.json

# Access shell
docker compose exec studio bash

# Stop
docker compose down

# Stop and remove volumes (clean slate)
docker compose down -v
```

### Files to Create

- [ ] `Dockerfile` - Multi-stage build for optimized image
- [ ] `Dockerfile.dev` - Development image with hot reload
- [ ] `docker-compose.yml` - Local development
- [ ] `docker-compose.staging.yml` - Staging environment
- [ ] `docker-compose.production.yml` - Production with HA
- [ ] `.dockerignore` - Exclude unnecessary files
- [ ] `nginx.conf` - Reverse proxy configuration
- [ ] `.env.example` - Environment variables template
- [ ] `scripts/deploy.sh` - Production deployment script
- [ ] `scripts/backup.sh` - Database backup script
- [ ] `docs/docker-deployment.md` - Detailed documentation

---

## 4. Web Portal Enhancement

Improve the standalone web frontend for operators and non-VSCode users.

### Current State
- Basic React frontend in `studio/frontend/`
- Pipeline visualization and execution
- No file system access from browser

### Design Philosophy

**VSCode Extension = Developer Authoring Tool (Native)**
- Full IDE integration (IntelliSense, diagnostics, debugging)
- Pipeline creation and editing
- Deep file system integration

**Web Portal = Operations & Monitoring Dashboard**
- Execution monitoring and history
- Run pipelines with custom inputs
- Admin panel (API keys, users, settings)
- For non-VSCode users and operators
- NOT trying to replicate VSCode editing experience

### Planned Features

#### Phase 1: Operations Dashboard
- [ ] Execution history with filtering and search
- [ ] Real-time execution monitoring
- [ ] Log viewer with streaming
- [ ] Pipeline run statistics and metrics
- [ ] Manual trigger UI with input form

#### Phase 2: Admin Panel
- [ ] API key management UI
- [ ] User and organization management
- [ ] SAML/SSO configuration wizard
- [ ] Audit log viewer
- [ ] System health and diagnostics

#### Phase 3: Pipeline Viewer (Read-Only)
- [ ] Visual pipeline graph (view only)
- [ ] Stage configuration viewer
- [ ] Component documentation browser
- [ ] Input/output schema explorer

#### Phase 4: Limited Editing (via MCP)
- [ ] Edit pipeline inputs/config (not structure)
- [ ] File operations via MCP integration
- [ ] Create new runs from templates
- [ ] Save execution results

### Target Users

| User Type | Primary Interface | Use Case |
|-----------|------------------|----------|
| Developer | VSCode Extension | Build, debug, test pipelines |
| DevOps | Web Portal | Deploy, monitor, troubleshoot |
| Business User | Web Portal | Run pipelines, view results |
| Admin | Web Portal | Manage users, API keys, settings |

---

## 5. MCP Integration (Model Context Protocol)

Native MCP support to make FlowMason AI-agent ready and enable unified resource access.

### Strategic Value

**FlowMason + MCP = The workflow platform for the AI era**

- First workflow tool with native MCP support
- AI agents can invoke pipelines as tools
- Unified file/resource access across VSCode, Web, CLI
- Automatic integration with growing MCP ecosystem

### Architecture Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                         MCP Ecosystem                           │
│                                                                 │
│   ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────────────┐   │
│   │ Claude  │  │ Cursor  │  │ Other   │  │ FlowMason       │   │
│   │ Desktop │  │ IDE     │  │ Agents  │  │ Web Portal      │   │
│   └────┬────┘  └────┬────┘  └────┬────┘  └────────┬────────┘   │
│        │            │            │                │            │
│        └────────────┴─────┬──────┴────────────────┘            │
│                           │                                    │
│                    MCP Protocol                                │
│                           │                                    │
│        ┌──────────────────┼──────────────────┐                 │
│        ▼                  ▼                  ▼                 │
│  ┌──────────┐      ┌──────────────┐   ┌──────────────┐        │
│  │Filesystem│      │  FlowMason   │   │  Database    │        │
│  │MCP Server│      │  MCP Server  │   │  MCP Server  │        │
│  └──────────┘      └──────────────┘   └──────────────┘        │
│        │                  │                  │                 │
│        ▼                  ▼                  ▼                 │
│   Local Files      Pipeline Engine      PostgreSQL             │
└─────────────────────────────────────────────────────────────────┘
```

### Part A: FlowMason as MCP Server

Expose FlowMason capabilities to AI agents and other MCP clients.

#### MCP Server Specification

```typescript
// FlowMason MCP Server capabilities
{
  "name": "flowmason",
  "version": "1.0.0",
  "capabilities": {
    "tools": true,
    "resources": true,
    "prompts": true
  }
}
```

#### Tools (Actions AI Can Invoke)

```typescript
tools: [
  {
    name: "pipelines/list",
    description: "List all available pipelines in the project",
    inputSchema: {
      type: "object",
      properties: {
        project_path: { type: "string", description: "Path to FlowMason project" },
        tags: { type: "array", items: { type: "string" }, description: "Filter by tags" }
      }
    }
  },
  {
    name: "pipelines/run",
    description: "Execute a FlowMason pipeline with given inputs",
    inputSchema: {
      type: "object",
      properties: {
        pipeline: { type: "string", description: "Pipeline name or path" },
        inputs: { type: "object", description: "Pipeline input values" },
        wait: { type: "boolean", default: true, description: "Wait for completion" }
      },
      required: ["pipeline"]
    }
  },
  {
    name: "pipelines/get-status",
    description: "Get the status of a pipeline execution",
    inputSchema: {
      type: "object",
      properties: {
        run_id: { type: "string", description: "Execution run ID" }
      },
      required: ["run_id"]
    }
  },
  {
    name: "pipelines/get-result",
    description: "Get the result of a completed pipeline execution",
    inputSchema: {
      type: "object",
      properties: {
        run_id: { type: "string", description: "Execution run ID" }
      },
      required: ["run_id"]
    }
  },
  {
    name: "components/list",
    description: "List all available components (operators, nodes)",
    inputSchema: {
      type: "object",
      properties: {
        category: { type: "string", description: "Filter by category" },
        type: { type: "string", enum: ["operator", "node", "all"] }
      }
    }
  },
  {
    name: "components/get-schema",
    description: "Get the input/output schema for a component",
    inputSchema: {
      type: "object",
      properties: {
        component_name: { type: "string", description: "Component name" }
      },
      required: ["component_name"]
    }
  }
]
```

#### Resources (Data AI Can Read)

```typescript
resources: [
  {
    uri: "pipeline://data-validation",
    name: "Data Validation Pipeline",
    description: "Validates and transforms input data",
    mimeType: "application/json"
  },
  {
    uri: "execution://run_abc123",
    name: "Execution Run abc123",
    description: "Results from pipeline execution",
    mimeType: "application/json"
  },
  {
    uri: "component://filter",
    name: "Filter Operator",
    description: "Conditionally filter data based on conditions",
    mimeType: "application/json"
  }
]
```

#### Prompts (Pre-built AI Interactions)

```typescript
prompts: [
  {
    name: "analyze-pipeline",
    description: "Analyze a pipeline and suggest improvements",
    arguments: [
      { name: "pipeline", description: "Pipeline to analyze", required: true }
    ]
  },
  {
    name: "debug-execution",
    description: "Help debug a failed pipeline execution",
    arguments: [
      { name: "run_id", description: "Failed execution run ID", required: true }
    ]
  },
  {
    name: "create-pipeline",
    description: "Help create a new pipeline based on requirements",
    arguments: [
      { name: "description", description: "What the pipeline should do", required: true }
    ]
  }
]
```

#### Use Cases: AI Agents Using FlowMason

**Example 1: Claude Desktop Running a Pipeline**
```
User: "Validate my customer data file and show me any issues"

Claude: I'll use FlowMason to validate your data.
        → MCP: pipelines/run {pipeline: "data-validation", inputs: {file: "customers.csv"}}

FlowMason: Executes pipeline, returns results

Claude: "I found 3 validation issues:
        - Row 45: Invalid email format 'john@'
        - Row 67: Duplicate customer ID 'CUST-001'
        - Row 89: Missing required field 'country'"
```

**Example 2: AI Agent Orchestrating Multiple Pipelines**
```
User: "Process this month's sales data and generate the executive report"

Claude: I'll run the sales processing workflow.
        → MCP: pipelines/run {pipeline: "sales-etl", inputs: {month: "2025-01"}}
        → MCP: pipelines/run {pipeline: "generate-report", inputs: {data: <etl-output>}}

Claude: "Done! The executive report is ready at reports/2025-01-sales.pdf
        Key highlights:
        - Revenue up 15% vs last month
        - Top performing region: West Coast
        - 3 products flagged for review"
```

**Example 3: Cursor IDE Integration**
```
Developer in Cursor: "Run the test pipeline on this JSON"

Cursor: → MCP: pipelines/run {pipeline: "test-transform", inputs: {data: <selected-json>}}

Result appears inline in editor
```

### Part B: FlowMason as MCP Client

Pipeline stages can consume MCP servers for unified resource access.

#### New MCP Operators

```yaml
# New operators that consume MCP resources
stages:
  - id: read-data
    component: mcp_resource
    config:
      server: "filesystem"  # or "s3", "postgres", etc.
      uri: "file:///data/input.csv"

  - id: query-db
    component: mcp_tool
    config:
      server: "postgres"
      tool: "query"
      arguments:
        sql: "SELECT * FROM customers WHERE active = true"

  - id: call-api
    component: mcp_tool
    config:
      server: "http"
      tool: "fetch"
      arguments:
        url: "https://api.example.com/data"
        method: "GET"
```

#### Environment Portability

```yaml
# Same pipeline works in any environment
# Just configure different MCP servers

# Local development (.env.local)
MCP_FILESYSTEM_ROOT=/Users/dev/projects/data
MCP_DATABASE_URL=sqlite:///local.db

# Staging (.env.staging)
MCP_FILESYSTEM_ROOT=s3://staging-bucket/data
MCP_DATABASE_URL=postgresql://staging-db/flowmason

# Production (.env.production)
MCP_FILESYSTEM_ROOT=s3://prod-bucket/data
MCP_DATABASE_URL=postgresql://prod-cluster/flowmason
```

#### Unified File Access for Web Portal

```
┌─────────────────┐     ┌─────────────────┐     ┌──────────────┐
│   Web Portal    │────▶│  Studio API     │────▶│  MCP Server  │
│   (Browser)     │     │  /api/v1/mcp/*  │     │  (filesystem)│
└─────────────────┘     └─────────────────┘     └──────────────┘
                                                       │
┌─────────────────┐                                    │
│ VSCode Extension│────────────────────────────────────┘
│   (MCP Client)  │     Same MCP server, same files
└─────────────────┘
```

### Part C: VSCode Extension MCP Integration

#### Extension as MCP Client

```typescript
// VSCode extension connects to FlowMason MCP server
import { Client } from "@modelcontextprotocol/sdk/client";

const mcpClient = new Client({
  name: "flowmason-vscode",
  version: "1.0.0"
});

// Connect to FlowMason MCP server
await mcpClient.connect(transport);

// List pipelines
const pipelines = await mcpClient.callTool("pipelines/list", {});

// Run pipeline
const result = await mcpClient.callTool("pipelines/run", {
  pipeline: "data-validation",
  inputs: { file: "test.csv" }
});
```

#### Extension Hosting MCP Server

```typescript
// VSCode extension can also HOST an MCP server
// Exposing VSCode workspace capabilities

const server = new Server({
  name: "flowmason-vscode-workspace",
  version: "1.0.0"
});

server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "workspace/read-file",
      description: "Read a file from the VSCode workspace",
      inputSchema: { /* ... */ }
    },
    {
      name: "workspace/write-file",
      description: "Write a file to the VSCode workspace",
      inputSchema: { /* ... */ }
    }
  ]
}));
```

### Implementation Phases

#### Phase 1: FlowMason MCP Server (Core)
- [ ] Implement MCP server in Python (`flowmason_core/mcp/`)
- [ ] `pipelines/list` tool
- [ ] `pipelines/run` tool
- [ ] `pipelines/get-status` tool
- [ ] `components/list` tool
- [ ] Pipeline resources
- [ ] CLI command: `fm mcp serve`
- [ ] Documentation for Claude Desktop integration

#### Phase 2: MCP Client Operators
- [ ] `mcp_resource` operator - read from any MCP resource
- [ ] `mcp_tool` operator - invoke any MCP tool
- [ ] MCP server configuration in `flowmason.json`
- [ ] Built-in filesystem MCP server
- [ ] Environment-based MCP server selection

#### Phase 3: VSCode Extension MCP
- [ ] Extension as MCP client (connect to FlowMason MCP server)
- [ ] Extension hosts workspace MCP server
- [ ] Unified file operations via MCP
- [ ] MCP server status in status bar

#### Phase 4: Web Portal MCP
- [ ] Studio API proxies MCP requests
- [ ] Web portal file browser via MCP
- [ ] Pipeline editing via MCP (limited)
- [ ] MCP server management UI

#### Phase 5: Advanced Features
- [ ] MCP prompts for AI-assisted pipeline creation
- [ ] Pipeline composition via AI
- [ ] Execution debugging with AI assistance
- [ ] Multi-server MCP routing

### Files to Create

```
core/flowmason_core/mcp/
├── __init__.py
├── server.py              # FlowMason MCP Server implementation
├── tools/
│   ├── __init__.py
│   ├── pipelines.py       # Pipeline-related tools
│   ├── components.py      # Component-related tools
│   └── executions.py      # Execution-related tools
├── resources/
│   ├── __init__.py
│   ├── pipeline.py        # Pipeline resources
│   └── execution.py       # Execution resources
└── prompts/
    ├── __init__.py
    └── templates.py       # AI prompt templates

lab/flowmason_lab/operators/mcp/
├── __init__.py
├── mcp_resource.py        # Read from MCP resources
└── mcp_tool.py            # Invoke MCP tools

vscode-extension/src/mcp/
├── client.ts              # MCP client for extension
└── server.ts              # Workspace MCP server
```

### Configuration

```json
// flowmason.json - MCP configuration
{
  "mcp": {
    "server": {
      "enabled": true,
      "port": 3000,
      "transport": "stdio"  // or "http", "websocket"
    },
    "clients": {
      "filesystem": {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/data"]
      },
      "postgres": {
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-postgres", "${DATABASE_URL}"]
      }
    }
  }
}
```

### Claude Desktop Integration

```json
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "flowmason": {
      "command": "fm",
      "args": ["mcp", "serve"],
      "env": {
        "FLOWMASON_PROJECT": "/path/to/project"
      }
    }
  }
}
```

---

## 6. AI Pipeline Generation

Enable AI assistants to generate valid FlowMason pipelines from natural language descriptions.

### Current State
- Created `PIPELINES.md` - comprehensive guide for AI assistants
- Documents pipeline structure, all components, patterns, and examples
- Can be used by Claude, ChatGPT, Copilot, Cursor, etc.

### Files Created

**`/PIPELINES.md`** - AI context file containing:
- Pipeline JSON structure
- Template syntax (`{{input.*}}`, `{{upstream.*}}`)
- All available components with examples:
  - Core: logger, json_transform, filter, variable_set, schema_validate
  - Control Flow: foreach, conditional, router
  - HTTP: http_request
  - AI/LLM: generator, critic, selector
- Pipeline patterns (ETL, Batch Processing, Conditional, AI Generation)
- Best practices
- Complete example pipeline
- Prompting tips for AI

### How to Use

**With Claude/ChatGPT:**
```
Read the PIPELINES.md file, then create a FlowMason pipeline that:
- Takes customer orders as input
- Validates the data
- Filters high-value orders (>$500)
- Generates a summary report
```

**With Cursor/Copilot:**
- Open PIPELINES.md in the workspace
- AI will use it as context for pipeline generation
- Type a comment describing what you want and autocomplete

**With Claude Desktop (via MCP):**
```
User: "Create a pipeline that processes survey responses"
Claude: [reads PIPELINES.md via MCP] Here's a FlowMason pipeline...
```

### Planned Enhancements

#### Phase 1: Documentation (Complete)
- [x] Create PIPELINES.md with full component reference
- [x] Include patterns and examples
- [x] Add prompting tips

#### Phase 2: Schema-Driven Generation
- [ ] Export JSON Schema for pipeline format
- [ ] Generate component schemas dynamically from code
- [ ] VSCode extension provides schema to AI assistants

#### Phase 3: Interactive Generation
- [ ] `/generate` command in VSCode extension
- [ ] Natural language input → pipeline JSON
- [ ] Preview and edit before saving
- [ ] Iterative refinement ("make it also filter by date")

#### Phase 4: MCP-Powered Generation
- [ ] `pipelines/generate` MCP tool
- [ ] AI can create pipelines programmatically
- [ ] Validation before returning result
- [ ] Suggest improvements to generated pipelines

### Example AI Interaction

```
User: Create a pipeline that analyzes customer feedback

AI: I'll create a FlowMason pipeline for customer feedback analysis.

{
  "name": "Customer Feedback Analysis",
  "version": "1.0.0",
  "description": "Analyzes customer feedback for sentiment and key themes",
  "input_schema": {
    "type": "object",
    "properties": {
      "feedback_items": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "id": { "type": "string" },
            "text": { "type": "string" },
            "date": { "type": "string" }
          }
        }
      }
    },
    "required": ["feedback_items"]
  },
  "stages": [
    {
      "id": "validate-input",
      "component_type": "schema_validate",
      "config": { ... },
      "depends_on": []
    },
    {
      "id": "analyze-sentiment",
      "component_type": "foreach",
      "config": {
        "items": "{{upstream.validate-input.data}}",
        "loop_stages": ["sentiment-analysis"]
      },
      "depends_on": ["validate-input"]
    },
    ...
  ]
}

This pipeline:
1. Validates the input feedback format
2. Analyzes sentiment for each feedback item
3. Groups feedback by sentiment
4. Generates a summary report

Would you like me to modify anything?
```

---

## 7. Component Visual Enhancement

Improve the visual appearance of pipeline components in both VSCode and Web interfaces.

### Current State

**Operator metadata exists but is underutilized:**
```python
@operator(
    name="filter",
    icon="filter",           # Lucide icon name
    color="#8B5CF6",         # Hex color
    category="core",
    tags=["filter", "condition", "branch"],
)
```

**Current rendering issues:**

| Interface | Issue |
|-----------|-------|
| VSCode DAG Canvas | Plain rectangles, no icons, no component colors |
| VSCode Components Tree | Generic ThemeIcons, no component colors |
| Web Frontend | Generic icons (Box/Zap), colors partially used |

### Planned Improvements

#### Phase 1: Use Component Colors & Icons

**VSCode DAG Canvas:**
```html
<!-- Current -->
<rect class="node-bg" fill="var(--vscode-editor-background)" />
<text class="node-label">filter</text>

<!-- Improved -->
<rect class="node-bg" fill="#8B5CF6" opacity="0.1" />
<rect class="node-header" fill="#8B5CF6" height="32" />
<text class="node-icon">🔍</text>  <!-- or SVG icon -->
<text class="node-label" fill="white">Filter</text>
```

**Web Frontend - Map icon names to Lucide:**
```typescript
const iconMap: Record<string, LucideIcon> = {
  'filter': Filter,
  'code': Code,
  'globe': Globe,
  'file-text': FileText,
  'repeat': Repeat,
  'variable': Variable,
  'shield-check': ShieldCheck,
  'share-2': Share2,
  'git-branch': GitBranch,
  'zap': Zap,
  'sparkles': Sparkles,
};
```

#### Phase 2: Component Shape by Type

Different visual shapes for different component types:

```
┌─────────────────┐     ╔═════════════════╗     ◆─────────────────◆
│   Operators     │     ║     Nodes       ║     │  Control Flow   │
│   (Rectangles)  │     ║   (Rounded)     ║     │   (Diamond)     │
└─────────────────┘     ╚═════════════════╝     ◆─────────────────◆

┌─────────────────┐     ┌─────────────────┐
│ ⚡ Filter       │     │ 🌐 HTTP Request │
│ ─────────────── │     │ ─────────────── │
│ condition:      │     │ url: api.com    │
│ item.status     │     │ method: GET     │
└─────────────────┘     └─────────────────┘
```

#### Phase 3: Visual Data Flow

Show input/output schemas on connection ports:

```
                    ┌──────────────────┐
    {items[]}  ──●──│  foreach         │──●── {results[]}
                    │  ────────────────│
                    │  items: input    │
                    └──────────────────┘
                             │
                     {current_item}
                             │
                             ▼
                    ┌──────────────────┐
                    │  transform       │
                    └──────────────────┘
```

#### Phase 4: Rich Component Cards

**Enhanced node design:**
```
┌────────────────────────────────────┐
│ ■■■■■■■■■■■■■■■■ (category color)  │
├────────────────────────────────────┤
│  🔍  Filter                    v1.1│
│      ──────────────────────────────│
│  ○ data        →    passed ●       │
│  ○ condition        data   ●       │
│                     reason ●       │
├────────────────────────────────────┤
│  Tags: filter, condition, branch   │
└────────────────────────────────────┘
```

### Implementation Details

#### Component Icon Mapping

```typescript
// vscode-extension/src/utils/componentIcons.ts
export const componentIcons: Record<string, string> = {
  // Core
  'filter': 'filter',
  'json_transform': 'code',
  'logger': 'file-text',
  'variable_set': 'variable',
  'schema_validate': 'shield-check',
  'http_request': 'globe',

  // Control Flow
  'foreach': 'repeat',
  'conditional': 'git-branch',
  'router': 'share-2',
  'loop': 'repeat',

  // AI/LLM
  'generator': 'sparkles',
  'critic': 'message-square',
  'selector': 'check-square',

  // Default
  'default_operator': 'zap',
  'default_node': 'box',
};

export const categoryColors: Record<string, string> = {
  'core': '#6366F1',      // Indigo
  'control_flow': '#EC4899', // Pink
  'ai': '#F59E0B',        // Amber
  'integration': '#3B82F6', // Blue
  'data': '#14B8A6',      // Teal
  'workspace': '#78716C', // Stone
};
```

#### VSCode Webview SVG Icons

```typescript
// Generate inline SVG from Lucide icon data
function getLucideIconSvg(iconName: string, color: string): string {
  const iconPaths = lucideIcons[iconName];
  return `
    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"
         viewBox="0 0 24 24" fill="none" stroke="${color}"
         stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      ${iconPaths}
    </svg>
  `;
}
```

#### API Enhancement

```python
# Add to registry API response
@dataclass
class ComponentInfo:
    name: str
    category: str
    description: str
    icon: str           # Lucide icon name
    color: str          # Hex color
    input_schema: dict  # For port visualization
    output_schema: dict # For port visualization
    tags: List[str]
    version: str
```

### Design Tokens

```css
/* Component design tokens */
:root {
  /* Category colors */
  --fm-core-color: #6366F1;
  --fm-control-flow-color: #EC4899;
  --fm-ai-color: #F59E0B;
  --fm-integration-color: #3B82F6;
  --fm-data-color: #14B8A6;

  /* Node styles */
  --fm-node-radius: 12px;
  --fm-node-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
  --fm-node-border: 2px solid;
  --fm-node-header-height: 36px;

  /* Port styles */
  --fm-port-size: 12px;
  --fm-port-color-input: #94A3B8;
  --fm-port-color-output: #22C55E;
}
```

### Files to Modify

**VSCode Extension:**
- [ ] `src/editors/dagCanvasProvider.ts` - Enhanced node rendering with icons/colors
- [ ] `src/views/componentsTree.ts` - Use component icons and colors
- [ ] `src/utils/componentIcons.ts` - Icon mapping (new file)
- [ ] `src/services/flowmasonService.ts` - Fetch icon/color from API

**Web Frontend:**
- [ ] `src/components/PipelineCanvas.tsx` - Use component icons
- [ ] `src/components/nodes/StageNode.tsx` - Enhanced node design
- [ ] `src/utils/componentIcons.ts` - Icon mapping
- [ ] `src/components/ComponentPalette.tsx` - Show icons in palette

**Backend:**
- [ ] `studio/flowmason_studio/api/routes/registry.py` - Include icon/color in response
- [ ] `core/flowmason_core/registry/extractor.py` - Extract icon/color metadata

### Mockups

**Current vs Improved - VSCode:**
```
CURRENT:                          IMPROVED:
┌─────────────┐                   ┌────────────────────┐
│ filter      │                   │ 🔍 Filter     v1.1 │
│ operator    │        →          │ ────────────────── │
└─────────────┘                   │ Filters data based │
                                  │ on conditions      │
                                  └────────────────────┘
                                  (with purple accent)
```

**Current vs Improved - Web:**
```
CURRENT:                          IMPROVED:
┌──────────────────┐              ┌──────────────────────┐
│ ⚡ filter        │              │ ■■■■■ (purple bar)   │
│ operator         │     →        │ 🔍 Filter            │
└──────────────────┘              │ ○ data    → passed ● │
                                  └──────────────────────┘
```

---

## 8. Scheduling & Triggers

Enable automated pipeline execution via schedules, webhooks, and event-driven triggers.

### Current State
- Pipelines can only be run manually (CLI, API, VSCode)
- No scheduling capability
- No webhook endpoints for external triggers

### Planned Features

#### Phase 1: Cron Scheduling

```yaml
# In pipeline.json or separate schedule.json
{
  "pipeline": "data-sync.pipeline.json",
  "schedule": {
    "cron": "0 */6 * * *",           # Every 6 hours
    "timezone": "America/New_York",
    "enabled": true
  },
  "default_inputs": {
    "source": "production"
  }
}
```

**Implementation:**
- [ ] Schedule configuration schema
- [ ] Scheduler service (APScheduler or similar)
- [ ] Schedule management API (`/api/v1/schedules`)
- [ ] VSCode UI for viewing/managing schedules
- [ ] Web portal schedule dashboard

#### Phase 2: Webhook Triggers

```yaml
{
  "pipeline": "process-order.pipeline.json",
  "webhook": {
    "path": "/hooks/new-order",
    "method": "POST",
    "auth": "bearer",                 # or "hmac", "api_key", "none"
    "input_mapping": {
      "order_id": "$.body.id",
      "customer": "$.body.customer"
    }
  }
}
```

**Webhook endpoints:**
```
POST /api/v1/hooks/{hook_id}
POST /api/v1/hooks/by-name/{hook_name}
```

**Features:**
- [ ] Webhook registration and management
- [ ] Multiple auth methods (Bearer, HMAC, API Key)
- [ ] Request body → pipeline input mapping
- [ ] Webhook logs and retry on failure
- [ ] Rate limiting per webhook

#### Phase 3: Event-Driven Triggers

```yaml
{
  "pipeline": "process-file.pipeline.json",
  "triggers": [
    {
      "type": "file_watch",
      "path": "/data/incoming/*.csv",
      "events": ["created", "modified"],
      "debounce_seconds": 5
    },
    {
      "type": "mcp_event",
      "server": "database",
      "event": "row_inserted",
      "table": "orders"
    },
    {
      "type": "pipeline_completed",
      "pipeline": "data-fetch.pipeline.json",
      "status": "success"
    }
  ]
}
```

**Trigger types:**
- [ ] File system watch (local, S3 via MCP)
- [ ] Pipeline completion (chain pipelines)
- [ ] Database events (via MCP)
- [ ] Message queue (Redis, RabbitMQ)
- [ ] Custom MCP events

#### Phase 4: Trigger Management UI

**VSCode Extension:**
```
SCHEDULES & TRIGGERS
├── 📅 Schedules
│   ├── data-sync (every 6h) ✓
│   └── daily-report (9am daily) ✓
├── 🔗 Webhooks
│   ├── /hooks/new-order
│   └── /hooks/payment-received
└── 👁️ Watchers
    └── /data/incoming/*.csv
```

**Web Portal:**
- Schedule calendar view
- Webhook testing UI
- Trigger history and logs
- Enable/disable toggles

### CLI Commands

```bash
# List schedules
fm schedule list

# Create schedule
fm schedule create daily-sync.pipeline.json --cron "0 9 * * *"

# Disable schedule
fm schedule disable daily-sync

# List webhooks
fm webhook list

# Test webhook
fm webhook test new-order --data '{"id": "123"}'

# View trigger history
fm triggers history --limit 50
```

### API Endpoints

```
# Schedules
GET    /api/v1/schedules
POST   /api/v1/schedules
GET    /api/v1/schedules/{id}
PUT    /api/v1/schedules/{id}
DELETE /api/v1/schedules/{id}
POST   /api/v1/schedules/{id}/run   # Manual trigger

# Webhooks
GET    /api/v1/webhooks
POST   /api/v1/webhooks
GET    /api/v1/webhooks/{id}
DELETE /api/v1/webhooks/{id}
POST   /api/v1/hooks/{hook_id}      # Webhook endpoint

# Trigger history
GET    /api/v1/triggers/history
```

---

## 9. Pipeline Testing Framework

Enable developers to write and run tests for pipelines before deployment.

### Current State
- No testing framework for pipelines
- Manual testing only
- No way to mock external dependencies

### Planned Features

#### Phase 1: Test Runner

```python
# tests/test_data_validation.py
import flowmason.testing as fm_test

def test_valid_records_pass():
    """Test that valid records pass validation."""
    result = fm_test.run(
        "pipelines/data-validation.pipeline.json",
        inputs={
            "records": [
                {"id": "1", "email": "user@example.com", "status": "active"},
                {"id": "2", "email": "admin@example.com", "status": "active"},
            ]
        }
    )

    assert result.success
    assert result.output["summary"]["total_records"] == 2
    assert result.output["summary"]["active_count"] == 2

def test_invalid_email_filtered():
    """Test that invalid emails are caught."""
    result = fm_test.run(
        "pipelines/data-validation.pipeline.json",
        inputs={
            "records": [
                {"id": "1", "email": "invalid-email", "status": "active"},
            ]
        }
    )

    assert result.success
    assert result.output["summary"]["validation_errors"] is not None
```

**CLI:**
```bash
# Run all tests
fm test

# Run specific test file
fm test tests/test_data_validation.py

# Run with coverage
fm test --coverage

# Run in watch mode
fm test --watch
```

#### Phase 2: Stage Mocking

```python
def test_with_mocked_http():
    """Test pipeline with mocked HTTP responses."""
    result = fm_test.run(
        "pipelines/fetch-and-process.pipeline.json",
        inputs={"url": "https://api.example.com/data"},
        mocks={
            "fetch-data": {
                "result": {"items": [{"id": 1}, {"id": 2}]},
                "status_code": 200
            },
            "send-notification": fm_test.SKIP  # Skip this stage
        }
    )

    assert result.success
    assert len(result.output["processed_items"]) == 2

def test_http_failure_handling():
    """Test error handling when HTTP fails."""
    result = fm_test.run(
        "pipelines/fetch-and-process.pipeline.json",
        inputs={"url": "https://api.example.com/data"},
        mocks={
            "fetch-data": fm_test.MockError(
                error="Connection timeout",
                status_code=504
            )
        }
    )

    # Pipeline should handle error gracefully
    assert result.stages["use-fallback"].status == "completed"
```

#### Phase 3: Snapshot Testing

```python
def test_transform_output_snapshot():
    """Test that transform output matches snapshot."""
    result = fm_test.run(
        "pipelines/data-transform.pipeline.json",
        inputs={"data": sample_data}
    )

    # First run creates snapshot, subsequent runs compare
    fm_test.assert_snapshot_match(
        result.output,
        snapshot_name="transform_output"
    )
```

**Snapshot files:**
```
tests/
├── snapshots/
│   └── test_transform_output_snapshot/
│       └── transform_output.json
└── test_transform.py
```

#### Phase 4: Integration Testing

```python
@fm_test.integration  # Marks as integration test (not run by default)
def test_full_pipeline_with_real_api():
    """Integration test with real API (requires network)."""
    result = fm_test.run(
        "pipelines/production-workflow.pipeline.json",
        inputs={"environment": "staging"},
        timeout=60
    )

    assert result.success

@fm_test.fixtures("sample_customers.json")
def test_with_fixture_data(sample_customers):
    """Test using fixture data."""
    result = fm_test.run(
        "pipelines/customer-analysis.pipeline.json",
        inputs={"customers": sample_customers}
    )

    assert result.success
```

### Test Configuration

```json
// flowmason.json
{
  "testing": {
    "test_dir": "tests",
    "fixtures_dir": "tests/fixtures",
    "snapshots_dir": "tests/snapshots",
    "timeout_seconds": 30,
    "parallel": true,
    "coverage": {
      "enabled": true,
      "threshold": 80
    }
  }
}
```

### VSCode Integration

- Test explorer integration
- Run tests from editor
- Debug tests with breakpoints
- Coverage highlighting

### Files to Create

```
core/flowmason_core/testing/
├── __init__.py
├── runner.py          # Test runner
├── mocks.py           # Stage mocking
├── assertions.py      # Custom assertions
├── snapshots.py       # Snapshot testing
└── fixtures.py        # Fixture loading

lab/flowmason_lab/operators/testing/
├── __init__.py
└── test_helpers.py    # Helper operators for testing
```

---

## 10. Secrets Management

Secure handling of API keys, credentials, and sensitive configuration.

### Current State
- Secrets stored in environment variables
- No encryption at rest
- No secret rotation
- No audit trail for secret access

### Planned Features

#### Phase 1: Encrypted Secret Storage

```yaml
# Reference secrets in pipelines
stages:
  - id: call-api
    component_type: http_request
    config:
      url: "https://api.stripe.com/v1/charges"
      headers:
        Authorization: "Bearer {{secrets.STRIPE_API_KEY}}"
```

**Secret storage:**
```python
# Secrets encrypted at rest using Fernet (AES-128)
# Master key from environment or hardware security module

@dataclass
class Secret:
    id: str
    name: str                    # e.g., "STRIPE_API_KEY"
    encrypted_value: bytes       # Fernet encrypted
    environment: str             # "development", "staging", "production"
    created_at: datetime
    updated_at: datetime
    created_by: str
    last_accessed_at: Optional[datetime]
    expires_at: Optional[datetime]
    tags: List[str]
```

#### Phase 2: Environment-Specific Secrets

```
Secrets
├── development
│   ├── STRIPE_API_KEY (test key)
│   ├── DATABASE_URL (local)
│   └── OPENAI_API_KEY
├── staging
│   ├── STRIPE_API_KEY (test key)
│   ├── DATABASE_URL (staging db)
│   └── OPENAI_API_KEY
└── production
    ├── STRIPE_API_KEY (live key)
    ├── DATABASE_URL (prod db)
    └── OPENAI_API_KEY
```

**Resolution order:**
1. Environment-specific secret
2. Shared secret
3. Environment variable (fallback)

#### Phase 3: Secret Access Control

```python
# Scoped access to secrets
class SecretScope:
    PIPELINE = "pipeline"      # Accessible during pipeline execution
    OPERATOR = "operator"      # Accessible by specific operators
    ADMIN = "admin"            # Only via admin API

# Pipeline-level secret permissions
{
    "pipeline": "payment-processing.pipeline.json",
    "secrets": ["STRIPE_API_KEY", "DATABASE_URL"],  # Allowed secrets
    "deny_secrets": ["ADMIN_PASSWORD"]               # Explicitly denied
}
```

#### Phase 4: Audit Trail

```python
@dataclass
class SecretAccessLog:
    id: str
    timestamp: datetime
    secret_name: str
    action: str                  # "read", "write", "delete", "rotate"
    accessor_type: str           # "pipeline", "user", "api_key"
    accessor_id: str
    pipeline_id: Optional[str]
    stage_id: Optional[str]
    ip_address: Optional[str]
    success: bool
```

**Audit queries:**
```bash
# View secret access history
fm secrets audit STRIPE_API_KEY --days 30

# View all access by pipeline
fm secrets audit --pipeline payment-processing --days 7
```

### CLI Commands

```bash
# Set a secret
fm secrets set STRIPE_API_KEY --env production
# (prompts for value, never shown in terminal)

# Set from file
fm secrets set TLS_CERT --from-file ./cert.pem --env production

# List secrets (names only, not values)
fm secrets list
fm secrets list --env staging

# Delete secret
fm secrets delete STRIPE_API_KEY --env development

# Rotate secret
fm secrets rotate STRIPE_API_KEY --env production

# View audit log
fm secrets audit --days 7
```

### API Endpoints

```
# Secret management (admin only)
GET    /api/v1/secrets                    # List secret names
POST   /api/v1/secrets                    # Create secret
PUT    /api/v1/secrets/{name}             # Update secret
DELETE /api/v1/secrets/{name}             # Delete secret
POST   /api/v1/secrets/{name}/rotate      # Rotate secret

# Secret access (internal, during execution)
GET    /api/v1/secrets/{name}/value       # Get decrypted value (logged)

# Audit
GET    /api/v1/secrets/audit              # Access audit log
```

### VSCode Integration

```
SECRETS
├── 🔐 development
│   ├── STRIPE_API_KEY ••••••••
│   ├── DATABASE_URL ••••••••
│   └── + Add Secret
├── 🔐 staging
│   └── ...
└── 🔐 production
    └── ...
```

- View secret names (not values)
- Add/update secrets via secure input
- Copy secret reference (`{{secrets.NAME}}`)
- View audit log

### Web Portal

- Secret management dashboard
- Environment comparison view
- Rotation reminders
- Access audit visualization

### Security Considerations

| Aspect | Implementation |
|--------|----------------|
| Encryption at rest | Fernet (AES-128-CBC) |
| Key management | Environment variable or HSM |
| Access control | Role-based, pipeline-scoped |
| Audit logging | All access logged |
| Secret rotation | Supported, optional expiry |
| Transport | HTTPS only, no logging of values |

### Files to Create

```
core/flowmason_core/secrets/
├── __init__.py
├── store.py           # Secret storage and encryption
├── resolver.py        # Template resolution {{secrets.X}}
├── audit.py           # Access audit logging
└── rotation.py        # Secret rotation

studio/flowmason_studio/api/routes/secrets.py
studio/flowmason_studio/services/secrets.py
```

---

## 11. API Console / Testing Interface (Web Portal)

An interactive chat-like interface in the FlowMason Web Portal for testing and exploring APIs.

### Current State
- API testing requires external tools (curl, Postman, etc.)
- Web portal lacks an integrated way to test pipelines
- Operations teams need to switch between portal and external tools
- No unified interface for API exploration and testing

### Concept

A dedicated page in the Web Portal that provides:
1. Chat-like interface for API interactions
2. Pipeline execution with real-time output
3. API exploration and documentation
4. Request/response history
5. Saved test requests and collections

### Mockup

```
┌─────────────────────────────────────────────────────────────────┐
│ FlowMason API Console                              [Settings] ⚙ │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 🤖 FlowMason Studio running at http://localhost:8999    │   │
│  │    Connected • 3 pipelines available                    │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 👤 Run data-validation with test data                   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 🤖 Running pipeline: data-validation                    │   │
│  │    ├── ✓ log-start (12ms)                               │   │
│  │    ├── ✓ validate-schema (45ms)                         │   │
│  │    ├── ✓ transform-records (23ms)                       │   │
│  │    ├── ✓ filter-active (8ms)                            │   │
│  │    └── ✓ create-summary (15ms)                          │   │
│  │                                                         │   │
│  │    Result: ✓ Success (103ms)                            │   │
│  │    ┌──────────────────────────────────────────────┐     │   │
│  │    │ {                                            │     │   │
│  │    │   "total_records": 5,                        │     │   │
│  │    │   "active_count": 3,                         │     │   │
│  │    │   "high_value_count": 2                      │     │   │
│  │    │ }                                            │     │   │
│  │    └──────────────────────────────────────────────┘     │   │
│  │    [Copy] [Save] [View Full Response]                   │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 👤 List all components                                  │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ 🤖 Found 12 components:                                 │   │
│  │    Core: filter, json_transform, logger, variable_set   │   │
│  │    Control Flow: foreach, conditional, router           │   │
│  │    HTTP: http_request                                   │   │
│  │    AI: generator, critic, selector, synthesizer         │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
├─────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Type a command or question...                         [↵] │ │
│ └─────────────────────────────────────────────────────────────┘ │
│                                                                 │
│ Quick: [Run Pipeline ▾] [List Pipelines] [Health] [Components] │
└─────────────────────────────────────────────────────────────────┘
```

### Features

#### Phase 1: Basic API Console

**Chat Commands:**
```
# Health check
health
→ Studio is healthy (v1.0.0)

# List pipelines
pipelines
list pipelines
→ Found 3 pipelines: data-validation, batch-processing, customer-triage

# Run pipeline
run data-validation
run data-validation {"records": [...]}
→ [Streaming execution output]

# Get run status
status run_abc123
→ Status: completed, Duration: 103ms

# List components
components
components --category core
→ Lists all available components
```

**API Explorer:**
```
# Direct API calls
GET /health
POST /api/v1/debug/run {"pipeline_path": "..."}
GET /api/v1/runs/{run_id}

# With autocomplete for endpoints and parameters
```

#### Phase 2: Interactive Features

**Input Builder:**
```
┌─────────────────────────────────────────┐
│ Run Pipeline: data-validation           │
├─────────────────────────────────────────┤
│ Input Schema:                           │
│ ┌─────────────────────────────────────┐ │
│ │ records* (array)                    │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ [                               │ │ │
│ │ │   {"id": "1", "email": "..."}   │ │ │
│ │ │ ]                               │ │ │
│ │ └─────────────────────────────────┘ │ │
│ │                                     │ │
│ │ threshold (number, default: 100)    │ │
│ │ [____100____]                       │ │
│ └─────────────────────────────────────┘ │
├─────────────────────────────────────────┤
│ [Load Sample] [Load from File] [Run ▶]  │
└─────────────────────────────────────────┘
```

**Real-time Execution View:**
```
Executing: data-validation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60%

├── ✓ log-start           12ms
├── ✓ validate-schema     45ms  [View Output]
├── ● transform-records   ...   ← Currently running
├── ○ filter-active
└── ○ create-summary

[Cancel] [Pause at Next Stage]
```

#### Phase 3: History & Saved Requests

```
HISTORY                              SAVED REQUESTS
├── Today                            ├── Test valid data
│   ├── run data-validation (✓)      ├── Test invalid emails
│   ├── run batch-processing (✗)     ├── Load test (100 items)
│   └── GET /health (✓)              └── Production sample
└── Yesterday
    └── ...
```

**Save request:**
```json
{
  "name": "Test valid data",
  "command": "run",
  "pipeline": "data-validation",
  "inputs": {
    "records": [...]
  },
  "description": "Happy path test with valid records"
}
```

#### Phase 4: AI-Assisted Testing

With MCP integration, the chat can understand natural language:

```
👤 "Run the data validation pipeline with 5 sample customers"
🤖 Generating sample data...
🤖 Running data-validation with 5 customers
🤖 ✓ Complete: 5 records processed, 3 active, 2 high-value

👤 "Now run it with an invalid email to test error handling"
🤖 Running with invalid email: "not-an-email"
🤖 ✓ Complete: Validation caught 1 error (invalid email format)

👤 "Compare the outputs"
🤖 Comparison:
   - Test 1: 5 valid → 5 processed
   - Test 2: 1 invalid → caught by validation
   Both handled correctly ✓
```

### Implementation

#### React Components (Web Portal Frontend)

```typescript
// studio/frontend/src/pages/ApiConsole.tsx
import { useState, useCallback } from 'react';
import { ChatMessage, ApiRequest, ExecutionResult } from '../types/console';
import { useStudioApi } from '../hooks/useStudioApi';
import { parseCommand } from '../utils/commandParser';

export function ApiConsolePage() {
    const [messages, setMessages] = useState<ChatMessage[]>([]);
    const [history, setHistory] = useState<ApiRequest[]>([]);
    const [savedRequests, setSavedRequests] = useState<ApiRequest[]>([]);
    const api = useStudioApi();

    const handleCommand = useCallback(async (input: string) => {
        const command = parseCommand(input);

        // Add user message
        setMessages(prev => [...prev, { type: 'user', content: input }]);

        try {
            let result: ExecutionResult;

            switch (command.type) {
                case 'run':
                    result = await api.runPipeline(command.pipeline, command.inputs);
                    break;
                case 'list':
                    result = await api.listResources(command.resource);
                    break;
                case 'health':
                    result = await api.healthCheck();
                    break;
                case 'api':
                    result = await api.rawRequest(command.method, command.path, command.body);
                    break;
            }

            // Add bot response
            setMessages(prev => [...prev, { type: 'bot', content: result }]);

            // Add to history
            setHistory(prev => [{ input, result, timestamp: Date.now() }, ...prev]);
        } catch (error) {
            setMessages(prev => [...prev, { type: 'error', content: error.message }]);
        }
    }, [api]);

    return (
        <div className="api-console">
            <ConsoleHeader />
            <ChatHistory messages={messages} />
            <CommandInput onSubmit={handleCommand} />
            <QuickActions onAction={handleCommand} />
            <Sidebar history={history} saved={savedRequests} />
        </div>
    );
}
```

#### Command Parser

```typescript
// studio/frontend/src/utils/commandParser.ts
interface Command {
    type: 'run' | 'list' | 'status' | 'health' | 'api' | 'unknown';
    pipeline?: string;
    inputs?: object;
    resource?: string;
    method?: string;
    path?: string;
    body?: object;
}

export function parseCommand(input: string): Command {
    const patterns = [
        { regex: /^(run|execute)\s+(\S+)(?:\s+(.+))?$/i, type: 'run' as const },
        { regex: /^(list\s+)?(pipelines?|components?|runs?)$/i, type: 'list' as const },
        { regex: /^(status|check)\s+(\S+)$/i, type: 'status' as const },
        { regex: /^health$/i, type: 'health' as const },
        { regex: /^(GET|POST|PUT|DELETE)\s+(\S+)(?:\s+(.+))?$/i, type: 'api' as const },
    ];

    for (const pattern of patterns) {
        const match = input.match(pattern.regex);
        if (match) {
            return buildCommand(pattern.type, match);
        }
    }

    return { type: 'unknown' };
}

function buildCommand(type: Command['type'], match: RegExpMatchArray): Command {
    switch (type) {
        case 'run':
            return {
                type,
                pipeline: match[2],
                inputs: match[3] ? JSON.parse(match[3]) : undefined
            };
        case 'api':
            return {
                type,
                method: match[1],
                path: match[2],
                body: match[3] ? JSON.parse(match[3]) : undefined
            };
        case 'list':
            return { type, resource: match[2] || 'pipelines' };
        default:
            return { type };
    }
}
```

#### Backend API Endpoints

```python
# studio/flowmason_studio/api/routes/console.py
from fastapi import APIRouter, Depends
from pydantic import BaseModel
from typing import Optional, List
from ..services.console_service import ConsoleService

router = APIRouter(prefix="/api/v1/console", tags=["console"])

class SavedRequest(BaseModel):
    name: str
    command: str
    inputs: Optional[dict] = None
    description: Optional[str] = None

@router.get("/history")
async def get_history(limit: int = 100, service: ConsoleService = Depends()):
    """Get command history for the current session"""
    return await service.get_history(limit)

@router.post("/saved")
async def save_request(request: SavedRequest, service: ConsoleService = Depends()):
    """Save a request for later reuse"""
    return await service.save_request(request)

@router.get("/saved")
async def list_saved_requests(service: ConsoleService = Depends()):
    """List all saved requests"""
    return await service.list_saved_requests()

@router.delete("/saved/{request_id}")
async def delete_saved_request(request_id: str, service: ConsoleService = Depends()):
    """Delete a saved request"""
    return await service.delete_saved_request(request_id)
```

### Files to Create

```
studio/frontend/src/
├── pages/
│   └── ApiConsole.tsx           # Main console page
├── components/console/
│   ├── ChatHistory.tsx          # Message display
│   ├── CommandInput.tsx         # Input with autocomplete
│   ├── QuickActions.tsx         # Quick action buttons
│   ├── ExecutionView.tsx        # Real-time execution display
│   ├── InputBuilder.tsx         # JSON input form builder
│   └── ConsoleSidebar.tsx       # History and saved requests
├── hooks/
│   └── useConsoleHistory.ts     # History state management
└── utils/
    └── commandParser.ts         # Command parsing logic

studio/flowmason_studio/api/routes/
└── console.py                   # Console-specific endpoints

studio/flowmason_studio/services/
└── console_service.py           # Console service (history, saved requests)
```

### Navigation Integration

```typescript
// studio/frontend/src/App.tsx - Add route
<Route path="/console" element={<ApiConsolePage />} />

// studio/frontend/src/components/Sidebar.tsx - Add nav item
<NavItem to="/console" icon={Terminal}>API Console</NavItem>
```

### Configuration

Console settings stored in portal (synced with backend):

```typescript
// Console preferences (stored per-user in portal)
interface ConsoleSettings {
    maxHistoryItems: number;      // Default: 100
    autoConnect: boolean;         // Default: true
    showTimestamps: boolean;      // Default: true
    jsonPrettyPrint: boolean;     // Default: true
    theme: 'auto' | 'light' | 'dark';
}
```

---

## 12. Pipeline Debugger with Time Travel

A visual debugger that lets you step through pipeline execution, inspect state at any point, and "rewind" to re-execute from any stage.

### Concept

Unlike traditional debuggers, FlowMason's debugger captures the complete execution state, allowing you to:
1. Set breakpoints on any stage
2. Step forward/backward through execution
3. Inspect inputs/outputs at any point
4. Modify data and re-run from that point
5. Compare different execution paths

### Mockup

```
┌─────────────────────────────────────────────────────────────────────────┐
│ FlowMason Debugger                    Run: run_abc123    [⏸ Paused]     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Timeline:                                                              │
│  ┌────┬────┬────┬────┬────┬────┬────┐                                   │
│  │ 1  │ 2  │ 3  │ 4  │ 5● │ 6  │ 7  │  ← Currently at stage 5          │
│  └────┴────┴────┴────┴────┴────┴────┘                                   │
│  [⏮] [◀] [▶] [⏭]  [↻ Restart]  [⏵ Continue]                            │
│                                                                         │
│  ┌─────────────────────────────┬───────────────────────────────────────┐│
│  │ Stage: filter-active        │ State Inspector                       ││
│  │ Status: ● Breakpoint        │                                       ││
│  │ Duration: --                │ Input:                                ││
│  │                             │ ┌─────────────────────────────────┐   ││
│  │ ○ log-start          ✓     │ │ {                               │   ││
│  │ ○ validate-schema    ✓     │ │   "data": [                     │   ││
│  │ ○ transform-records  ✓     │ │     {"id": "1", "status": ...}  │   ││
│  │ ● filter-active      ⏸     │ │   ],                            │   ││
│  │ ○ filter-high-score        │ │   "condition": "item.get..."    │   ││
│  │ ○ create-summary           │ │ }                               │   ││
│  │                             │ └─────────────────────────────────┘   ││
│  │ Breakpoints:                │                                       ││
│  │ ☑ filter-active            │ [Edit & Re-run] [Step Into]           ││
│  │ ☐ create-summary           │                                       ││
│  └─────────────────────────────┴───────────────────────────────────────┘│
│                                                                         │
│  Execution History:                                                     │
│  ┌─────────────────────────────────────────────────────────────────────┐│
│  │ #5 filter-active: Received 10 items, condition="item.get('status')" ││
│  │ #4 transform-records: Transformed 10 → 10 items (100%)              ││
│  │ #3 validate-schema: Validation passed, 0 errors                     ││
│  │ #2 log-start: "Starting ETL pipeline"                               ││
│  └─────────────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────────────┘
```

### Features

#### Time Travel Debugging
```python
# Backend stores execution snapshots
class ExecutionSnapshot:
    stage_id: str
    timestamp: datetime
    inputs: dict
    outputs: dict
    context: dict
    variables: dict

# API endpoints
POST /api/v1/debug/breakpoint/{run_id}/{stage_id}  # Set breakpoint
POST /api/v1/debug/step/{run_id}                    # Step to next stage
POST /api/v1/debug/rewind/{run_id}/{stage_id}      # Rewind to stage
POST /api/v1/debug/modify/{run_id}/{stage_id}      # Modify and continue
GET  /api/v1/debug/snapshot/{run_id}/{stage_id}    # Get snapshot
```

#### Edit & Re-run
Modify the input data at any snapshot point and re-execute from there:
```
1. Pause at stage 5
2. Edit the input data (fix a bug, test edge case)
3. Click "Re-run from here"
4. Execution continues from stage 5 with modified data
5. Original execution preserved for comparison
```

#### Comparison Mode
```
┌─────────────────────────────┬─────────────────────────────┐
│ Original Run                │ Modified Run                │
├─────────────────────────────┼─────────────────────────────┤
│ filter-active: 3 passed     │ filter-active: 5 passed     │
│ Duration: 45ms              │ Duration: 52ms              │
│                             │                             │
│ Output:                     │ Output:                     │
│ ["USR001", "USR002", ...]   │ ["USR001", "USR002", ...]   │
│                             │ + "USR003", "USR005"        │
└─────────────────────────────┴─────────────────────────────┘
```

---

## 13. LLM Cost Tracking & Optimization

Track, analyze, and optimize LLM API costs across all pipeline executions.

### Concept

AI-powered pipelines can get expensive. FlowMason tracks every LLM call, provides cost analytics, and suggests optimizations.

### Dashboard

```
┌─────────────────────────────────────────────────────────────────────────┐
│ LLM Cost Analytics                                  Period: Last 30 days │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Total Spend: $847.23                    Budget: $1,000/month           │
│  ████████████████████████░░░░ 85%                                       │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ $                                                                │   │
│  │ 50 ┤                              ╭─╮                            │   │
│  │ 40 ┤                    ╭────────╯  ╰──╮                         │   │
│  │ 30 ┤       ╭────────────╯              ╰────╮                    │   │
│  │ 20 ┤  ╭────╯                                ╰────                │   │
│  │ 10 ┤──╯                                                          │   │
│  │    └─────────────────────────────────────────────────────────────│   │
│  │      1    5    10   15   20   25   30                            │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Cost by Pipeline:                    Cost by Model:                    │
│  ┌────────────────────────────┐       ┌────────────────────────────┐   │
│  │ customer-triage    $312.45 │       │ claude-3-opus     $523.00  │   │
│  │ content-generator  $287.12 │       │ claude-3-sonnet   $198.45  │   │
│  │ code-reviewer      $156.89 │       │ gpt-4-turbo       $125.78  │   │
│  │ summarizer          $90.77 │       │ claude-3-haiku     $0.00   │   │
│  └────────────────────────────┘       └────────────────────────────┘   │
│                                                                         │
│  💡 Optimization Suggestions:                                           │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 1. customer-triage uses opus for classification - haiku would   │   │
│  │    work equally well. Potential savings: $280/month             │   │
│  │                                                   [Apply Fix]   │   │
│  │                                                                 │   │
│  │ 2. content-generator has redundant summarization step.          │   │
│  │    Consider caching. Potential savings: $95/month               │   │
│  │                                                   [View Details]│   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
```

### Features

#### Automatic Cost Tracking
```python
# Tracked automatically for every LLM call
class LLMUsage:
    run_id: str
    stage_id: str
    provider: str          # anthropic, openai, etc.
    model: str             # claude-3-opus, gpt-4, etc.
    input_tokens: int
    output_tokens: int
    cost_usd: float
    latency_ms: int
    timestamp: datetime
```

#### Budget Alerts
```yaml
# flowmason.yaml
cost_management:
  monthly_budget: 1000
  alerts:
    - threshold: 80%
      action: email
    - threshold: 95%
      action: pause_non_critical
    - threshold: 100%
      action: pause_all

  # Per-pipeline limits
  pipeline_limits:
    customer-triage: 500
    content-generator: 300
```

#### Model Comparison Testing
Run the same pipeline with different models to compare cost vs. quality:
```
A/B Test: customer-triage classification step

| Model           | Accuracy | Cost/1000 | Latency |
|-----------------|----------|-----------|---------|
| claude-3-opus   | 98.2%    | $15.00    | 2.1s    |
| claude-3-sonnet | 96.8%    | $3.00     | 0.8s    |
| claude-3-haiku  | 94.1%    | $0.25     | 0.2s    |
| gpt-4-turbo     | 97.5%    | $10.00    | 1.5s    |

Recommendation: Use haiku for initial triage, escalate to sonnet for
uncertain cases. Projected savings: 78%
```

---

## 14. Pipeline Versioning & Rollback

Git-like versioning for pipelines with instant rollback capabilities.

### Concept

Every pipeline change is tracked. Deploy with confidence knowing you can instantly rollback to any previous version.

### Version History

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Pipeline: customer-triage                                    [Deploy ▾] │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Current: v2.3.1 (production)                                           │
│                                                                         │
│  Version History:                                                       │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ v2.3.1  ● LIVE    "Fix threshold for high-priority"   2h ago   │   │
│  │                   by sam@company.com                            │   │
│  │                   [View] [Diff] [Rollback]                      │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ v2.3.0           "Add sentiment analysis stage"       1d ago   │   │
│  │                   by alex@company.com                           │   │
│  │                   [View] [Diff] [Restore]                       │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ v2.2.0           "Optimize LLM prompts"               3d ago   │   │
│  │                   by sam@company.com                            │   │
│  │                   [View] [Diff] [Restore]                       │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ v2.1.0           "Add email notification"             1w ago   │   │
│  │                   [View] [Diff] [Restore]                       │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  [Compare Versions ▾]  [Create Branch]  [View All Tags]                 │
└─────────────────────────────────────────────────────────────────────────┘
```

### Features

#### Visual Diff
```
┌─────────────────────────────────────────────────────────────────────────┐
│ Comparing: v2.2.0 → v2.3.0                                              │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Pipeline Changes:                                                      │
│  + Added stage: sentiment-analysis (after classify-intent)              │
│  ~ Modified stage: route-ticket (added sentiment condition)             │
│                                                                         │
│  Stage: sentiment-analysis (NEW)                                        │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ + {                                                             │   │
│  │ +   "id": "sentiment-analysis",                                 │   │
│  │ +   "component_type": "generator",                              │   │
│  │ +   "config": {                                                 │   │
│  │ +     "prompt": "Analyze the sentiment of: {{input.message}}"   │   │
│  │ +   }                                                           │   │
│  │ + }                                                             │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Stage: route-ticket (MODIFIED)                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │   "conditions": [                                               │   │
│  │     { "when": "priority == 'high'", "goto": "urgent-queue" },   │   │
│  │ +   { "when": "sentiment == 'angry'", "goto": "escalation" },   │   │
│  │     { "default": true, "goto": "standard-queue" }               │   │
│  │   ]                                                             │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
```

#### Instant Rollback
```bash
# CLI
fm rollback customer-triage --to v2.2.0

# API
POST /api/v1/pipelines/customer-triage/rollback
{ "target_version": "v2.2.0" }

# Result: Pipeline instantly reverted, new version v2.3.2 created
```

#### Deployment Environments
```yaml
# environments.yaml
environments:
  development:
    auto_deploy: true
    version: latest

  staging:
    auto_deploy: false
    version: v2.3.1
    approval_required: false

  production:
    auto_deploy: false
    version: v2.3.0
    approval_required: true
    approvers: ["lead@company.com", "ops@company.com"]
```

---

## 15. Prompt Library & A/B Testing

Centralized prompt management with version control and A/B testing capabilities.

### Concept

Prompts are first-class citizens. Store them centrally, version them, and A/B test variations to optimize performance.

### Prompt Library

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Prompt Library                                          [+ New Prompt]  │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Search: [________________________]  Filter: [All Categories ▾]         │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 📝 customer-classification                              v3.2    │   │
│  │    "Classify customer intent into categories..."                │   │
│  │    Used in: customer-triage, support-bot                        │   │
│  │    Performance: 96.2% accuracy │ A/B Test: Running              │   │
│  │    [Edit] [Duplicate] [View A/B Results]                        │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ 📝 content-summarizer                                   v2.1    │   │
│  │    "Summarize the following content in 2-3 sentences..."        │   │
│  │    Used in: news-digest, report-generator                       │   │
│  │    Performance: 4.7/5 quality │ A/B Test: None                  │   │
│  │    [Edit] [Duplicate] [Start A/B Test]                          │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ 📝 code-review-feedback                                 v1.5    │   │
│  │    "Review this code and provide constructive feedback..."      │   │
│  │    Used in: pr-reviewer, code-mentor                            │   │
│  │    Performance: 89% helpful │ A/B Test: Completed               │   │
│  │    [Edit] [Duplicate] [View History]                            │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
```

### A/B Testing Interface

```
┌─────────────────────────────────────────────────────────────────────────┐
│ A/B Test: customer-classification                        Status: Active │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Test Configuration:                                                    │
│  ├─ Traffic Split: 50% / 50%                                           │
│  ├─ Sample Size: 1,000 (682 completed)                                 │
│  ├─ Success Metric: classification_accuracy                            │
│  └─ Started: 2 days ago                                                │
│                                                                         │
│  ┌──────────────────────────────┬──────────────────────────────┐       │
│  │ Variant A (Control)          │ Variant B (Challenger)       │       │
│  │ v3.1                         │ v3.2-beta                    │       │
│  ├──────────────────────────────┼──────────────────────────────┤       │
│  │ "Classify the customer       │ "You are a customer service  │       │
│  │ message into one of these    │ expert. Analyze this message │       │
│  │ categories: billing,         │ and determine the customer's │       │
│  │ technical, sales, general"   │ primary intent. Categories:  │       │
│  │                              │ billing, technical, sales,   │       │
│  │                              │ general. Also rate urgency." │       │
│  ├──────────────────────────────┼──────────────────────────────┤       │
│  │ Accuracy: 94.8%              │ Accuracy: 97.1%              │       │
│  │ Avg Tokens: 145              │ Avg Tokens: 198              │       │
│  │ Cost/1000: $0.43             │ Cost/1000: $0.59             │       │
│  │ Latency: 0.8s                │ Latency: 1.1s                │       │
│  └──────────────────────────────┴──────────────────────────────┘       │
│                                                                         │
│  Statistical Significance: 94% (need 95% to declare winner)            │
│  Estimated completion: 6 hours                                         │
│                                                                         │
│  [End Test - Keep A] [End Test - Keep B] [Extend Test] [Cancel]        │
└─────────────────────────────────────────────────────────────────────────┘
```

### Prompt Templates with Variables

```yaml
# prompts/customer-classification.yaml
name: customer-classification
version: 3.2
description: Classify customer intent from support messages
category: classification

template: |
  You are a customer service expert at {{company_name}}.

  Analyze this customer message and determine:
  1. Primary intent: {{categories}}
  2. Urgency: low, medium, high, critical
  3. Sentiment: positive, neutral, negative

  Customer message:
  {{message}}

  Respond in JSON format.

variables:
  company_name:
    type: string
    default: "our company"
  categories:
    type: array
    default: ["billing", "technical", "sales", "general"]
  message:
    type: string
    required: true

metadata:
  model_recommendation: claude-3-haiku
  expected_tokens: 150-250
  use_cases:
    - customer-triage
    - support-bot
```

### Usage in Pipeline

```json
{
  "id": "classify-intent",
  "component_type": "generator",
  "config": {
    "prompt_ref": "prompts://customer-classification@v3.2",
    "prompt_variables": {
      "company_name": "Acme Corp",
      "message": "{{input.customer_message}}"
    }
  }
}
```

---

## 16. Pipeline Marketplace

A community marketplace for sharing and discovering pipeline templates, components, and integrations.

### Concept

An ecosystem where users can:
1. Publish and share pipeline templates
2. Discover pre-built solutions for common use cases
3. Monetize their components (optional)
4. Rate and review community contributions

### Marketplace Interface

```
┌─────────────────────────────────────────────────────────────────────────┐
│ FlowMason Marketplace                               [Publish] [My Items]│
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  [Templates] [Components] [Integrations] [Prompts]                      │
│                                                                         │
│  Search: [________________________]  Sort: [Most Popular ▾]             │
│                                                                         │
│  Featured Templates                                                     │
│  ┌────────────────────┬────────────────────┬────────────────────┐      │
│  │ 🎯 Customer Support│ 📊 Data Analytics  │ 🤖 Content Gen     │      │
│  │    Triage          │    Pipeline        │    Suite           │      │
│  │                    │                    │                    │      │
│  │ Automatically route│ ETL + transform +  │ Blog posts, social │      │
│  │ support tickets    │ visualization      │ media, newsletters │      │
│  │                    │                    │                    │      │
│  │ ⭐ 4.8 (234)       │ ⭐ 4.6 (189)       │ ⭐ 4.9 (412)       │      │
│  │ 📥 1.2k installs   │ 📥 890 installs    │ 📥 2.1k installs   │      │
│  │ FREE               │ FREE               │ $29                │      │
│  │ [Install] [Preview]│ [Install] [Preview]│ [Purchase][Preview]│      │
│  └────────────────────┴────────────────────┴────────────────────┘      │
│                                                                         │
│  Popular Components                                                     │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 🔌 slack-notifier         Send notifications to Slack    FREE   │   │
│  │    by @flowmason-team     ⭐ 4.9 (567)  📥 3.4k                  │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ 🔌 pdf-extractor          Extract text/tables from PDFs  $9     │   │
│  │    by @doctools           ⭐ 4.7 (123)  📥 890                   │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ 🔌 salesforce-sync        Bi-directional Salesforce sync $49    │   │
│  │    by @enterprise-int     ⭐ 4.5 (78)   📥 234                   │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Categories: [CRM] [Analytics] [AI/ML] [DevOps] [Marketing] [More ▾]   │
└─────────────────────────────────────────────────────────────────────────┘
```

### Template Detail Page

```
┌─────────────────────────────────────────────────────────────────────────┐
│ 🎯 Customer Support Triage                              [★ Star] [Fork] │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  by @enterprise-solutions  │  v2.1.0  │  Updated 3 days ago             │
│  ⭐ 4.8 (234 reviews)  │  📥 1,247 installs  │  MIT License              │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                     [Pipeline Preview DAG]                       │   │
│  │   ┌──────┐    ┌──────────┐    ┌────────┐    ┌──────────┐        │   │
│  │   │Intake│───▶│Classify  │───▶│Route   │───▶│Notify    │        │   │
│  │   └──────┘    └──────────┘    └────────┘    └──────────┘        │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Description:                                                           │
│  Automatically classify and route customer support tickets using AI.    │
│  Integrates with Zendesk, Intercom, and Freshdesk. Includes sentiment   │
│  analysis and urgency detection.                                        │
│                                                                         │
│  Features:                                                              │
│  ✓ Intent classification (12 categories)                               │
│  ✓ Sentiment & urgency analysis                                        │
│  ✓ Auto-routing to appropriate teams                                   │
│  ✓ SLA-based prioritization                                            │
│  ✓ Slack/Email notifications                                           │
│                                                                         │
│  Requirements:                                                          │
│  • FlowMason >= 0.7.0                                                  │
│  • API keys: Anthropic or OpenAI                                       │
│  • Optional: Zendesk, Slack credentials                                │
│                                                                         │
│  [Install to Project]  [View Source]  [Try in Playground]              │
│                                                                         │
│  Reviews:                                                               │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ ⭐⭐⭐⭐⭐ "Saved us 20 hours/week on ticket routing"              │   │
│  │ @startup-cto, 2 weeks ago                                        │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ ⭐⭐⭐⭐ "Great template, needed some customization for our use"  │   │
│  │ @support-lead, 1 month ago                                       │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 17. Real-time Collaboration

Google Docs-style real-time collaboration for pipeline editing.

### Concept

Multiple team members can edit the same pipeline simultaneously, see each other's cursors, and collaborate in real-time.

### Collaborative Editor

```
┌─────────────────────────────────────────────────────────────────────────┐
│ customer-triage.pipeline.json               👤 Sam 👤 Alex 👤 Jordan    │
│                                              ↑ 3 collaborators          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │   ┌──────────┐        ┌──────────┐        ┌──────────┐         │   │
│  │   │ intake   │───────▶│ classify │───────▶│ route    │         │   │
│  │   └──────────┘        └────┬─────┘        └──────────┘         │   │
│  │        │                   │ 👤 Alex                            │   │
│  │        │              (editing)                                 │   │
│  │        │                                                        │   │
│  │        │              ┌──────────┐        ┌──────────┐         │   │
│  │        └─────────────▶│ sentiment│───────▶│ escalate │         │   │
│  │           👤 Sam      └──────────┘        └──────────┘         │   │
│  │         (selecting)                            │                │   │
│  │                                          👤 Jordan              │   │
│  │                                         (editing)               │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 💬 Comments (3)                                        [+ Add]  │   │
│  │─────────────────────────────────────────────────────────────────│   │
│  │ 📍 On "classify" stage:                                         │   │
│  │    Alex: Should we add a confidence threshold?                  │   │
│  │    └─ Sam: Good idea, I'll add it                              │   │
│  │                                                                 │   │
│  │ 📍 On "escalate" stage:                                         │   │
│  │    Jordan: This should also trigger PagerDuty for critical     │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Activity:                                                              │
│  • Alex modified "classify" stage config (just now)                    │
│  • Sam added new stage "sentiment" (2 min ago)                         │
│  • Jordan joined the session (5 min ago)                               │
└─────────────────────────────────────────────────────────────────────────┘
```

### Features

#### Presence & Cursors
- See who's viewing/editing
- Real-time cursor positions
- Stage selection highlighting per user

#### Inline Comments
- Comment on specific stages
- Threaded discussions
- @mentions and notifications
- Resolve/archive comments

#### Change Attribution
```json
{
  "stages": [
    {
      "id": "classify",
      "_meta": {
        "last_modified_by": "alex@company.com",
        "last_modified_at": "2025-12-13T14:32:00Z"
      }
    }
  ]
}
```

#### Conflict Resolution
```
┌─────────────────────────────────────────────────────────────────────────┐
│ ⚠️ Conflict Detected on "classify" stage                                │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  You and Alex both modified the same config at the same time.           │
│                                                                         │
│  Your change:                    Alex's change:                         │
│  ┌───────────────────────────┐   ┌───────────────────────────────────┐ │
│  │ "threshold": 0.8          │   │ "threshold": 0.85                 │ │
│  │ "model": "claude-3-haiku" │   │ "model": "claude-3-sonnet"        │ │
│  └───────────────────────────┘   └───────────────────────────────────┘ │
│                                                                         │
│  [Keep Yours] [Keep Alex's] [Merge Both] [Open Chat]                   │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 18. Execution Analytics & Insights

Deep analytics on pipeline performance with AI-powered insights and anomaly detection.

### Dashboard

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Pipeline Analytics: customer-triage                    Period: 7 days   │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Overview                                                               │
│  ┌────────────────┬────────────────┬────────────────┬────────────────┐ │
│  │ Total Runs     │ Success Rate   │ Avg Duration   │ P95 Latency    │ │
│  │    12,847      │    98.2%       │    1.3s        │    2.8s        │ │
│  │   ↑ 23%        │   ↑ 0.5%       │   ↓ 0.2s       │   ↓ 0.4s       │ │
│  └────────────────┴────────────────┴────────────────┴────────────────┘ │
│                                                                         │
│  Execution Timeline                                                     │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ runs                                                            │   │
│  │ 200 ┤     ╭─╮                                                   │   │
│  │ 150 ┤  ╭──╯ ╰──╮    ╭────╮                    ╭──╮              │   │
│  │ 100 ┤──╯       ╰────╯    ╰────────────────────╯  ╰──            │   │
│  │  50 ┤                                                           │   │
│  │     └───────────────────────────────────────────────────────────│   │
│  │       Mon    Tue    Wed    Thu    Fri    Sat    Sun             │   │
│  │                                                                 │   │
│  │  ━ Successful  ━ Failed  ━ Timeout                              │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Stage Performance                                                      │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ Stage             │ Avg Time │ P95    │ Failures │ % of Total   │   │
│  │───────────────────┼──────────┼────────┼──────────┼──────────────│   │
│  │ intake            │   45ms   │  82ms  │    0     │ ██░░░░ 3%    │   │
│  │ classify          │  890ms   │ 1.8s   │   12     │ ████████ 68% │   │
│  │ sentiment         │  245ms   │ 520ms  │    3     │ ████░░░ 19%  │   │
│  │ route             │   23ms   │  45ms  │    0     │ █░░░░░ 2%    │   │
│  │ notify            │  102ms   │ 234ms  │    8     │ ██░░░░ 8%    │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  🤖 AI Insights                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 1. ⚠️ Anomaly detected: "classify" stage latency increased 40%  │   │
│  │    since Wednesday. Correlates with increased input length.     │   │
│  │    Suggestion: Add input truncation or switch to streaming.     │   │
│  │                                                                 │   │
│  │ 2. 💡 The "notify" stage fails primarily during 9-10am (peak).  │   │
│  │    Likely Slack rate limiting. Consider batching notifications. │   │
│  │                                                                 │   │
│  │ 3. ✨ Weekend traffic is 60% lower. Consider cost savings by    │   │
│  │    reducing reserved capacity during off-peak hours.            │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
```

### Anomaly Detection

```yaml
# analytics.yaml
alerts:
  - name: latency_spike
    condition: p95_latency > baseline * 1.5
    window: 1h
    action:
      - slack: "#ops-alerts"
      - email: ["oncall@company.com"]

  - name: error_rate
    condition: error_rate > 5%
    window: 15m
    action:
      - pagerduty: high
      - auto_rollback: true  # Rollback to last stable version

  - name: cost_anomaly
    condition: hourly_cost > daily_average * 3
    action:
      - slack: "#cost-alerts"
      - throttle: 50%  # Reduce throughput to 50%
```

---

## 19. Multi-Region Deployment

Deploy pipelines across multiple regions for low latency and high availability.

### Concept

Run pipelines closer to your users with automatic failover and load balancing.

### Architecture

```
                           ┌─────────────────┐
                           │  Global Router  │
                           │  (DNS/Anycast)  │
                           └────────┬────────┘
                                    │
            ┌───────────────────────┼───────────────────────┐
            │                       │                       │
            ▼                       ▼                       ▼
   ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
   │   US-EAST       │    │   EU-WEST       │    │   APAC          │
   │   (Primary)     │    │   (Replica)     │    │   (Replica)     │
   │                 │    │                 │    │                 │
   │  ┌───────────┐  │    │  ┌───────────┐  │    │  ┌───────────┐  │
   │  │ FlowMason │  │    │  │ FlowMason │  │    │  │ FlowMason │  │
   │  │  Studio   │  │    │  │  Studio   │  │    │  │  Studio   │  │
   │  └───────────┘  │    │  └───────────┘  │    │  └───────────┘  │
   │                 │    │                 │    │                 │
   │  ┌───────────┐  │    │  ┌───────────┐  │    │  ┌───────────┐  │
   │  │  Workers  │  │    │  │  Workers  │  │    │  │  Workers  │  │
   │  └───────────┘  │    │  └───────────┘  │    │  └───────────┘  │
   └─────────────────┘    └─────────────────┘    └─────────────────┘
            │                       │                       │
            └───────────────────────┴───────────────────────┘
                                    │
                           ┌────────▼────────┐
                           │  Shared State   │
                           │  (CockroachDB/  │
                           │   Spanner)      │
                           └─────────────────┘
```

### Configuration

```yaml
# deployment.yaml
multi_region:
  enabled: true

  regions:
    - name: us-east-1
      role: primary
      capacity: 100

    - name: eu-west-1
      role: replica
      capacity: 50
      sync_delay: 100ms

    - name: ap-southeast-1
      role: replica
      capacity: 30
      sync_delay: 200ms

  routing:
    strategy: latency  # latency, round-robin, geo
    failover:
      enabled: true
      threshold: 3  # failures before failover
      cooldown: 60s

  pipelines:
    customer-triage:
      regions: [us-east-1, eu-west-1]  # Not in APAC
      affinity: user_region

    global-analytics:
      regions: all
      affinity: data_region  # Process data where it lives
```

### Dashboard

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Multi-Region Status                                                     │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐     │
│  │    US-EAST      │    │    EU-WEST      │    │     APAC        │     │
│  │   ● Primary     │    │   ● Healthy     │    │   ● Healthy     │     │
│  │                 │    │                 │    │                 │     │
│  │  Load: 67%      │    │  Load: 45%      │    │  Load: 23%      │     │
│  │  Latency: 45ms  │    │  Latency: 12ms  │    │  Latency: 8ms   │     │
│  │  Runs: 5,234/hr │    │  Runs: 3,102/hr │    │  Runs: 1,456/hr │     │
│  └─────────────────┘    └─────────────────┘    └─────────────────┘     │
│                                                                         │
│  Traffic Distribution                                                   │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ US-EAST:    ████████████████████████████░░░░░░░░░░░░░░  54%     │   │
│  │ EU-WEST:    ███████████████████░░░░░░░░░░░░░░░░░░░░░░░  32%     │   │
│  │ APAC:       ███████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  14%     │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Recent Events:                                                         │
│  • 14:32 - EU-WEST: Auto-scaled from 3 to 5 workers                    │
│  • 12:15 - APAC: Brief latency spike (resolved)                        │
│  • 09:00 - US-EAST: Deployed v2.3.1 (propagated to all regions)        │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 20. Natural Language Pipeline Builder

Create and modify pipelines using natural language instructions.

### Concept

Talk to FlowMason like you would to a colleague. Describe what you want, and it builds the pipeline.

### Interface

```
┌─────────────────────────────────────────────────────────────────────────┐
│ FlowMason AI Builder                                      [New Session] │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 👤 I need a pipeline that takes customer feedback emails,       │   │
│  │    analyzes the sentiment, extracts key issues, and creates     │   │
│  │    tickets in our system. High-priority issues should go to     │   │
│  │    Slack immediately.                                           │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 🤖 I'll create a pipeline for that. Here's what I'm thinking:   │   │
│  │                                                                 │   │
│  │    1. **Email Intake** - Receive and parse incoming emails      │   │
│  │    2. **Sentiment Analysis** - Detect positive/negative/neutral │   │
│  │    3. **Issue Extraction** - Use AI to identify key problems    │   │
│  │    4. **Priority Assignment** - Based on sentiment + keywords   │   │
│  │    5. **Ticket Creation** - Create tickets in your system       │   │
│  │    6. **Slack Alert** - Notify for high-priority only           │   │
│  │                                                                 │   │
│  │    Questions:                                                   │   │
│  │    • What ticketing system do you use? (Jira, Linear, etc.)    │   │
│  │    • What makes an issue "high priority" for you?               │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 👤 We use Linear. High priority = negative sentiment AND        │   │
│  │    mentions "urgent", "broken", or "can't access"               │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 🤖 Perfect! I've created the pipeline:                          │   │
│  │                                                                 │   │
│  │    ┌───────┐   ┌───────┐   ┌───────┐   ┌───────┐   ┌───────┐   │   │
│  │    │Intake │──▶│Analyze│──▶│Extract│──▶│Route  │──▶│Linear │   │   │
│  │    └───────┘   └───────┘   └───────┘   └───┬───┘   └───────┘   │   │
│  │                                            │                    │   │
│  │                                            ▼ (high priority)    │   │
│  │                                       ┌───────┐                 │   │
│  │                                       │ Slack │                 │   │
│  │                                       └───────┘                 │   │
│  │                                                                 │   │
│  │    [View Pipeline JSON] [Open in Editor] [Run Test]            │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 👤 Actually, can you also add a step that auto-replies to the   │   │
│  │    customer acknowledging their feedback?                       │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ 🤖 Done! I've added an "Auto-Reply" stage after intake that     │   │
│  │    sends a personalized acknowledgment email. The template      │   │
│  │    includes the ticket ID so customers can track their issue.   │   │
│  │                                                                 │   │
│  │    [Show Changes] [Undo] [Continue]                            │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
├─────────────────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Describe what you want to build or modify...                   [↵] │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```

### Modification Mode

Also works on existing pipelines:

```
👤 "In my customer-triage pipeline, add rate limiting so we don't
    process more than 100 tickets per minute"

🤖 I've added a rate limiter stage before the classify step:

   Changes:
   + Added "rate-limiter" stage (100 req/min, queue overflow)
   + Modified "classify" depends_on to include rate-limiter

   [Apply Changes] [Show Diff] [Explain More]
```

```
👤 "The sentiment analysis is too slow. Can you optimize it?"

🤖 I analyzed your sentiment stage. Here are optimization options:

   1. **Switch to Haiku** - Currently using Sonnet (890ms avg)
      Haiku would be ~200ms with 94% accuracy (vs 97%)

   2. **Add caching** - 30% of your inputs are similar
      Could reduce LLM calls by ~25%

   3. **Batch processing** - Process 5 items per LLM call
      Would reduce latency to ~180ms per item

   Recommendation: Option 1 + 2 for best cost/performance

   [Apply Option 1] [Apply Option 2] [Apply Both] [Explain Trade-offs]
```

---

## 21. Pipeline Observability with OpenTelemetry

First-class distributed tracing and observability integration.

### Concept

Every pipeline execution generates OpenTelemetry traces, enabling deep visibility and integration with existing observability stacks.

### Trace View

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Trace: run_abc123                                Duration: 1,847ms       │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Timeline:                                                              │
│  0ms                500ms              1000ms             1500ms         │
│  │                   │                   │                   │          │
│  ├── pipeline.execute ─────────────────────────────────────────┤        │
│  │   │                                                         │        │
│  │   ├── stage.intake ████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░    │        │
│  │   │   └── http.request ██░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░    │        │
│  │   │                                                         │        │
│  │   ├── stage.classify ░░░░████████████████░░░░░░░░░░░░░░░    │        │
│  │   │   └── llm.anthropic ░░░░███████████████░░░░░░░░░░░░░    │        │
│  │   │       model: claude-3-haiku                             │        │
│  │   │       tokens: 234 in / 89 out                           │        │
│  │   │                                                         │        │
│  │   ├── stage.route ░░░░░░░░░░░░░░░░░░░░██░░░░░░░░░░░░░░░░    │        │
│  │   │                                                         │        │
│  │   └── stage.notify ░░░░░░░░░░░░░░░░░░░░░░████████░░░░░░░    │        │
│  │       └── http.slack ░░░░░░░░░░░░░░░░░░░░░███████░░░░░░░    │        │
│  │           status: 200                                       │        │
│  │                                                                      │
│  Span Details: stage.classify                                           │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │ Attributes:                                                     │   │
│  │   flowmason.stage.id: "classify"                               │   │
│  │   flowmason.stage.type: "generator"                            │   │
│  │   flowmason.run.id: "run_abc123"                               │   │
│  │   llm.provider: "anthropic"                                    │   │
│  │   llm.model: "claude-3-haiku-20240307"                         │   │
│  │   llm.input_tokens: 234                                        │   │
│  │   llm.output_tokens: 89                                        │   │
│  │   llm.cost_usd: 0.000089                                       │   │
│  │                                                                 │   │
│  │ Events:                                                         │   │
│  │   • prompt_sent (t+523ms)                                      │   │
│  │   • response_received (t+1,412ms)                              │   │
│  │   • parsed_output (t+1,418ms)                                  │   │
│  └─────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────┘
```

### Integration

```yaml
# flowmason.yaml
observability:
  tracing:
    enabled: true
    exporter: otlp
    endpoint: "https://otel-collector.company.com:4317"

    # What to trace
    spans:
      pipeline: true
      stage: true
      llm_calls: true
      http_requests: true

    # Sampling
    sampling:
      strategy: parent_based  # or always_on, always_off, ratio
      ratio: 0.1  # 10% of traces

  metrics:
    enabled: true
    exporter: prometheus
    port: 9090

  logging:
    enabled: true
    format: json
    level: info
```

### Grafana Dashboard

```
┌─────────────────────────────────────────────────────────────────────────┐
│ FlowMason Overview                                              Grafana │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Pipeline Throughput                    Error Rate                      │
│  ┌─────────────────────────┐           ┌─────────────────────────┐     │
│  │  ▁▂▃▄▅▆▇█▇▆▅▄▃▂▁       │           │  ▁▁▁▂▁▁▁█▁▁▁▁▁▁▁       │     │
│  │  1,234 req/min          │           │  0.8%                    │     │
│  └─────────────────────────┘           └─────────────────────────┘     │
│                                                                         │
│  P95 Latency by Stage                  LLM Cost (24h)                   │
│  ┌─────────────────────────┐           ┌─────────────────────────┐     │
│  │  intake:     ██ 82ms    │           │  Anthropic: $45.23      │     │
│  │  classify:   ████████   │           │  OpenAI:    $12.89      │     │
│  │              1,823ms    │           │  Total:     $58.12      │     │
│  │  route:      █ 45ms     │           │                         │     │
│  │  notify:     ███ 234ms  │           │  ↑ 12% from yesterday   │     │
│  └─────────────────────────┘           └─────────────────────────┘     │
│                                                                         │
│  Trace Search:                                                          │
│  [pipeline="customer-triage" AND duration>2s AND status=error]         │
│                                                                         │
│  Results: 23 traces                                                     │
│  • run_xyz789 - 3.2s - timeout in classify                             │
│  • run_abc456 - 2.8s - LLM rate limit                                  │
│  • run_def123 - 2.1s - Slack API error                                 │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## 22. Embedded FlowMason (SDK)

Embed FlowMason pipelines directly into your applications.

### Concept

Run pipelines as a library within your application - no separate server required.

### Python SDK

```python
from flowmason import Pipeline, FlowMason

# Initialize FlowMason (embedded mode)
fm = FlowMason(
    mode="embedded",
    providers={
        "anthropic": {"api_key": os.environ["ANTHROPIC_API_KEY"]}
    }
)

# Load pipeline from file
pipeline = fm.load_pipeline("./pipelines/customer-triage.pipeline.json")

# Or define inline
pipeline = Pipeline(
    name="quick-classifier",
    stages=[
        Stage(
            id="classify",
            component="generator",
            config={
                "prompt": "Classify this text: {{input.text}}",
                "model": "claude-3-haiku"
            }
        )
    ]
)

# Execute synchronously
result = pipeline.run({"text": "I need help with billing"})
print(result.output)  # {"category": "billing", "confidence": 0.95}

# Execute asynchronously
async def process_batch(items):
    tasks = [pipeline.run_async(item) for item in items]
    results = await asyncio.gather(*tasks)
    return results

# Stream results
async for event in pipeline.stream({"text": "..."}):
    if event.type == "stage_complete":
        print(f"Stage {event.stage_id} completed")
    elif event.type == "output":
        print(f"Final output: {event.data}")
```

### TypeScript/Node SDK

```typescript
import { FlowMason, Pipeline } from '@flowmason/sdk';

// Initialize
const fm = new FlowMason({
  mode: 'embedded',
  providers: {
    anthropic: { apiKey: process.env.ANTHROPIC_API_KEY }
  }
});

// Load and run
const pipeline = await fm.loadPipeline('./pipelines/customer-triage.json');
const result = await pipeline.run({ text: 'Need billing help' });

// With Express middleware
import { flowmasonMiddleware } from '@flowmason/sdk/express';

app.use('/api/pipelines', flowmasonMiddleware({
  pipelines: {
    'classify': './pipelines/classifier.json',
    'summarize': './pipelines/summarizer.json'
  }
}));

// POST /api/pipelines/classify { "text": "..." }
// Returns pipeline output
```

### React Hooks

```typescript
import { usePipeline, useFlowMason } from '@flowmason/react';

function CustomerForm() {
  const { run, loading, result, error } = usePipeline('customer-triage');

  const handleSubmit = async (data) => {
    const output = await run(data);
    // Handle result
  };

  return (
    <form onSubmit={handleSubmit}>
      {loading && <Spinner />}
      {error && <Error message={error} />}
      {result && <Result data={result} />}
    </form>
  );
}

// Or with streaming
function StreamingChat() {
  const { stream, events, isStreaming } = usePipelineStream('chat-pipeline');

  return (
    <div>
      {events.map(event => (
        <div key={event.id}>
          {event.type === 'stage_start' && `Running ${event.stage}...`}
          {event.type === 'output' && event.data}
        </div>
      ))}
    </div>
  );
}
```

---

## Priority Matrix

| Feature | Impact | Effort | Priority |
|---------|--------|--------|----------|
| **Docker - Local Dev** | High | Low | **P1** |
| Execution Endpoint Auth | High | Low | P1 |
| Local .fmpkg Import | High | Low | P1 |
| **MCP Server (Core)** | Very High | Medium | **P1** |
| **AI Pipeline Generation (Docs)** | High | Low | **P1 - DONE** |
| **Component Visual - Icons & Colors** | High | Low | **P1** |
| **Secrets Management (Basic)** | High | Medium | **P1** |
| **Docker - Staging** | High | Medium | **P2** |
| OAuth 2.0 Support | High | Medium | P2 |
| Standalone JWT Tokens | Medium | Medium | P2 |
| Built-in Template Gallery | High | Medium | P2 |
| **Docker - Production** | High | Medium | **P2** |
| **Web Portal - Operations Dashboard** | High | Medium | **P2** |
| **Web Portal - API Console** | High | Medium | **P2** |
| **MCP Client Operators** | High | Medium | **P2** |
| **Web Portal - Admin Panel** | Medium | Medium | **P2** |
| **AI Generation - Interactive** | High | Medium | **P2** |
| **Component Visual - Shapes & Ports** | Medium | Medium | **P2** |
| **Pipeline Testing - Basic Runner** | High | Medium | **P2** |
| **Scheduling - Cron** | High | Medium | **P2** |
| **Webhook Triggers** | High | Medium | **P2** |
| **Pipeline Debugger (Basic)** | High | Medium | **P2** |
| **LLM Cost Tracking** | High | Medium | **P2** |
| **Pipeline Versioning** | High | Medium | **P2** |
| **Prompt Library** | High | Medium | **P2** |
| **Embedded SDK (Python)** | Very High | Medium | **P2** |
| Remote Registry | High | High | P3 |
| Pipeline-Level Permissions | High | High | P3 |
| **VSCode Extension MCP** | High | Medium | **P3** |
| **Web Portal MCP Integration** | High | Medium | **P3** |
| **MCP Advanced (AI-assisted)** | Very High | High | **P3** |
| **AI Generation - MCP Tool** | Very High | Medium | **P3** |
| **Component Visual - Rich Cards** | Medium | High | **P3** |
| **Pipeline Testing - Mocking & Snapshots** | Medium | Medium | **P3** |
| **Event-Driven Triggers** | Medium | High | **P3** |
| **Secrets - Rotation & Audit** | Medium | Medium | **P3** |
| **Debugger - Time Travel** | High | High | **P3** |
| **Prompt A/B Testing** | High | High | **P3** |
| **Pipeline Marketplace** | Very High | Very High | **P3** |
| **Real-time Collaboration** | High | Very High | **P3** |
| **Execution Analytics & AI Insights** | High | High | **P3** |
| **Multi-Region Deployment** | High | Very High | **P3** |
| **Natural Language Builder** | Very High | High | **P3** |
| **OpenTelemetry Integration** | High | Medium | **P3** |
| **Embedded SDK (TypeScript)** | High | Medium | **P3** |
| **Embedded SDK (React Hooks)** | Medium | Low | **P3** |
| **Code Gen - Python** | Very High | High | **P2** |
| **Code Gen - Node.js/TypeScript** | Very High | High | **P2** |
| **Code Gen - Salesforce Apex** | High | High | **P3** |
| **Code Gen - Go/Java/Rust** | Medium | High | **P4** |
| **Code Gen - Serverless (Lambda/Workers)** | High | Medium | **P3** |
| **Visual Field Mapping (Basic)** | Very High | Medium | **P2** |
| **Visual Field Mapping (Schema Inference)** | High | Medium | **P2** |
| **Visual Field Mapping (Validation)** | High | Low | **P2** |

## 23. Pipeline-to-Code Generation

Compile FlowMason pipelines into standalone backend applications in multiple languages.

### Concept

Transform declarative pipeline JSON into production-ready code that runs independently - no FlowMason runtime required. Perfect for:
- Deploying to restricted environments
- Maximum performance (native code vs. interpreted)
- Integration with existing codebases
- Enterprise platforms (Salesforce Apex)

### Supported Targets

```
┌─────────────────────────────────────────────────────────────────────────┐
│ Pipeline Code Generator                                                 │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  Source: customer-triage.pipeline.json                                  │
│                                                                         │
│  Generate Code:                                                         │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                                                                 │   │
│  │  🐍 Python                              [Generate]              │   │
│  │     FastAPI service with async execution                        │   │
│  │     Output: customer_triage/                                    │   │
│  │             ├── main.py                                         │   │
│  │             ├── stages/                                         │   │
│  │             ├── requirements.txt                                │   │
│  │             └── Dockerfile                                      │   │
│  │                                                                 │   │
│  │  📦 Node.js / TypeScript               [Generate]              │   │
│  │     Express/Fastify service with TypeScript                     │   │
│  │     Output: customer-triage/                                    │   │
│  │             ├── src/                                            │   │
│  │             ├── package.json                                    │   │
│  │             └── Dockerfile                                      │   │
│  │                                                                 │   │
│  │  ☁️ Salesforce Apex                    [Generate]              │   │
│  │     Apex classes with Flow integration                          │   │
│  │     Output: force-app/main/default/                             │   │
│  │             ├── classes/                                        │   │
│  │             ├── flows/                                          │   │
│  │             └── triggers/                                       │   │
│  │                                                                 │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                                                                         │
│  Options:                                                               │
│  ☑ Include tests          ☑ Add Docker support                         │
│  ☑ Generate API docs      ☐ Inline all dependencies                    │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘
```

### Python Generation

**Input Pipeline:**
```json
{
  "name": "customer-triage",
  "stages": [
    {
      "id": "classify",
      "component_type": "generator",
      "config": {
        "prompt": "Classify: {{input.message}}",
        "model": "claude-3-haiku"
      }
    },
    {
      "id": "route",
      "component_type": "router",
      "config": {
        "conditions": [
          { "when": "priority == 'high'", "goto": "urgent" },
          { "default": true, "goto": "standard" }
        ]
      }
    }
  ]
}
```

**Generated Python:**
```python
# customer_triage/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import anthropic
import asyncio
from typing import Optional

app = FastAPI(title="Customer Triage API", version="1.0.0")
client = anthropic.AsyncAnthropic()

class TriageInput(BaseModel):
    message: str

class TriageOutput(BaseModel):
    classification: dict
    route: str
    priority: str

@app.post("/triage", response_model=TriageOutput)
async def triage_customer(input: TriageInput) -> TriageOutput:
    # Stage: classify
    classification = await classify_message(input.message)

    # Stage: route
    route = route_by_priority(classification)

    return TriageOutput(
        classification=classification,
        route=route,
        priority=classification.get("priority", "normal")
    )

async def classify_message(message: str) -> dict:
    """Generated from: classify stage (generator)"""
    response = await client.messages.create(
        model="claude-3-haiku-20240307",
        max_tokens=256,
        messages=[{
            "role": "user",
            "content": f"Classify: {message}"
        }]
    )
    return parse_json_response(response.content[0].text)

def route_by_priority(classification: dict) -> str:
    """Generated from: route stage (router)"""
    priority = classification.get("priority")

    if priority == "high":
        return "urgent"
    else:
        return "standard"

# --- Generated utilities ---
def parse_json_response(text: str) -> dict:
    import json
    import re
    # Extract JSON from markdown code blocks if present
    match = re.search(r'```(?:json)?\s*([\s\S]*?)\s*```', text)
    if match:
        text = match.group(1)
    return json.loads(text)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
```

**Generated requirements.txt:**
```
fastapi>=0.104.0
uvicorn>=0.24.0
anthropic>=0.18.0
pydantic>=2.0.0
```

**Generated Dockerfile:**
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

### Node.js/TypeScript Generation

**Generated TypeScript:**
```typescript
// src/index.ts
import Anthropic from "@anthropic-ai/sdk";
import Fastify from "fastify";

const app = Fastify({ logger: true });
const anthropic = new Anthropic();

interface TriageInput {
  message: string;
}

interface TriageOutput {
  classification: Record<string, unknown>;
  route: string;
  priority: string;
}

// Stage: classify
async function classifyMessage(message: string): Promise<Record<string, unknown>> {
  const response = await anthropic.messages.create({
    model: "claude-3-haiku-20240307",
    max_tokens: 256,
    messages: [{ role: "user", content: `Classify: ${message}` }],
  });

  return parseJsonResponse(
    response.content[0].type === "text" ? response.content[0].text : ""
  );
}

// Stage: route
function routeByPriority(classification: Record<string, unknown>): string {
  const priority = classification.priority;

  if (priority === "high") {
    return "urgent";
  }
  return "standard";
}

// Main pipeline endpoint
app.post<{ Body: TriageInput }>("/triage", async (request, reply) => {
  const { message } = request.body;

  // Execute pipeline stages
  const classification = await classifyMessage(message);
  const route = routeByPriority(classification);

  const output: TriageOutput = {
    classification,
    route,
    priority: (classification.priority as string) || "normal",
  };

  return output;
});

// Start server
app.listen({ port: 8000, host: "0.0.0.0" }, (err) => {
  if (err) throw err;
  console.log("Server running on http://0.0.0.0:8000");
});
```

### Salesforce Apex Generation

**Generated Apex Class:**
```java
// CustomerTriageService.cls
public class CustomerTriageService {

    public class TriageInput {
        @AuraEnabled public String message { get; set; }
    }

    public class TriageOutput {
        @AuraEnabled public Map<String, Object> classification { get; set; }
        @AuraEnabled public String route { get; set; }
        @AuraEnabled public String priority { get; set; }
    }

    @AuraEnabled(cacheable=false)
    public static TriageOutput triageCustomer(TriageInput input) {
        // Stage: classify
        Map<String, Object> classification = classifyMessage(input.message);

        // Stage: route
        String route = routeByPriority(classification);

        TriageOutput output = new TriageOutput();
        output.classification = classification;
        output.route = route;
        output.priority = (String) classification.get('priority');

        return output;
    }

    private static Map<String, Object> classifyMessage(String message) {
        // Call Claude API via Named Credential
        HttpRequest req = new HttpRequest();
        req.setEndpoint('callout:Anthropic_API/v1/messages');
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('anthropic-version', '2023-06-01');

        Map<String, Object> body = new Map<String, Object>{
            'model' => 'claude-3-haiku-20240307',
            'max_tokens' => 256,
            'messages' => new List<Map<String, String>>{
                new Map<String, String>{
                    'role' => 'user',
                    'content' => 'Classify: ' + message
                }
            }
        };
        req.setBody(JSON.serialize(body));

        Http http = new Http();
        HttpResponse res = http.send(req);

        Map<String, Object> response = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
        List<Object> content = (List<Object>) response.get('content');
        Map<String, Object> textBlock = (Map<String, Object>) content[0];
        String text = (String) textBlock.get('text');

        return (Map<String, Object>) JSON.deserializeUntyped(text);
    }

    private static String routeByPriority(Map<String, Object> classification) {
        String priority = (String) classification.get('priority');

        if (priority == 'high') {
            return 'urgent';
        }
        return 'standard';
    }
}
```

**Generated Apex Test:**
```java
// CustomerTriageServiceTest.cls
@isTest
public class CustomerTriageServiceTest {

    @isTest
    static void testTriageHighPriority() {
        // Mock the HTTP callout
        Test.setMock(HttpCalloutMock.class, new AnthropicMock('{"priority": "high", "category": "billing"}'));

        CustomerTriageService.TriageInput input = new CustomerTriageService.TriageInput();
        input.message = 'URGENT: My account is locked!';

        Test.startTest();
        CustomerTriageService.TriageOutput output = CustomerTriageService.triageCustomer(input);
        Test.stopTest();

        System.assertEquals('urgent', output.route, 'High priority should route to urgent');
        System.assertEquals('high', output.priority);
    }

    @isTest
    static void testTriageNormalPriority() {
        Test.setMock(HttpCalloutMock.class, new AnthropicMock('{"priority": "normal", "category": "inquiry"}'));

        CustomerTriageService.TriageInput input = new CustomerTriageService.TriageInput();
        input.message = 'What are your business hours?';

        Test.startTest();
        CustomerTriageService.TriageOutput output = CustomerTriageService.triageCustomer(input);
        Test.stopTest();

        System.assertEquals('standard', output.route, 'Normal priority should route to standard');
    }
}
```

**Generated Flow (metadata):**
```xml
<!-- CustomerTriageFlow.flow-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <label>Customer Triage Flow</label>
    <processType>AutoLaunchedFlow</processType>

    <actionCalls>
        <name>Triage_Customer</name>
        <label>Triage Customer</label>
        <actionName>CustomerTriageService</actionName>
        <actionType>apex</actionType>
        <inputParameters>
            <name>input</name>
            <value>
                <elementReference>inputRecord</elementReference>
            </value>
        </inputParameters>
        <outputParameters>
            <assignToReference>outputResult</assignToReference>
            <name>output</name>
        </outputParameters>
    </actionCalls>
</Flow>
```

### CLI Usage

```bash
# Generate Python backend
fm generate python customer-triage.pipeline.json -o ./output/python

# Generate Node.js/TypeScript
fm generate node customer-triage.pipeline.json -o ./output/node --typescript

# Generate Salesforce Apex
fm generate apex customer-triage.pipeline.json -o ./output/salesforce

# Options
fm generate python pipeline.json \
  --include-tests \
  --include-docker \
  --api-framework fastapi \  # or flask, starlette
  --async-mode \
  --output-dir ./backend
```

### API Endpoint

```python
# POST /api/v1/generate
{
  "pipeline_path": "pipelines/customer-triage.pipeline.json",
  "target": "python",
  "options": {
    "framework": "fastapi",
    "include_tests": true,
    "include_docker": true,
    "async_mode": true
  }
}

# Response: ZIP file with generated project
```

### Generation Architecture

```
┌─────────────────────────────────────────────────────────────────────────┐
│                        Pipeline Code Generator                          │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  ┌─────────────┐     ┌─────────────────┐     ┌────────────────────┐    │
│  │   Pipeline  │────▶│  IR Generator   │────▶│  Target Emitter    │    │
│  │    JSON     │     │                 │     │                    │    │
│  └─────────────┘     │ • Parse stages  │     │ ┌────────────────┐ │    │
│                      │ • Resolve deps  │     │ │ Python Emitter │ │    │
│                      │ • Build DAG     │     │ └────────────────┘ │    │
│                      │ • Type inference│     │ ┌────────────────┐ │    │
│                      └─────────────────┘     │ │ Node Emitter   │ │    │
│                              │               │ └────────────────┘ │    │
│                              ▼               │ ┌────────────────┐ │    │
│                      ┌─────────────────┐     │ │ Apex Emitter   │ │    │
│                      │ Intermediate    │     │ └────────────────┘ │    │
│                      │ Representation  │────▶│                    │    │
│                      │                 │     └────────────────────┘    │
│                      │ • StageNode[]   │              │                │
│                      │ • DataFlow      │              ▼                │
│                      │ • TypeMap       │     ┌────────────────────┐    │
│                      └─────────────────┘     │  Post-Processor    │    │
│                                              │                    │    │
│                                              │ • Format code      │    │
│                                              │ • Add imports      │    │
│                                              │ • Generate tests   │    │
│                                              │ • Create Dockerfile│    │
│                                              └────────────────────┘    │
│                                                       │                │
│                                                       ▼                │
│                                              ┌────────────────────┐    │
│                                              │   Output Project   │    │
│                                              │   (ZIP or folder)  │    │
│                                              └────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────┘
```

### Component Mappings

Each FlowMason component maps to language-specific implementations:

| Component | Python | Node.js | Apex |
|-----------|--------|---------|------|
| `generator` | `anthropic.messages.create()` | `anthropic.messages.create()` | `HttpRequest` to Named Credential |
| `json_transform` | `jmespath.search()` | `jmespath.search()` | Custom JSON utility class |
| `filter` | List comprehension | `Array.filter()` | SOQL or List iteration |
| `http_request` | `httpx.AsyncClient` | `fetch` / `axios` | `HttpRequest` |
| `conditional` | `if/elif/else` | `if/else if/else` | `if/else` |
| `foreach` | `async for` / `asyncio.gather` | `Promise.all` / `for await` | `for` loop |
| `router` | Match statement | Switch/if chain | `if/else` chain |

### Future Targets

Planned additional language targets:

```
• Go           - Chi/Gin REST service
• Java         - Spring Boot application
• Rust         - Axum/Actix service
• C#           - ASP.NET Core / Azure Functions
• AWS Lambda   - Python/Node handlers with SAM template
• Cloudflare   - Workers with Hono
• Deno         - Fresh/Oak service
```

---

## 24. Visual Field Mapping Between Nodes

A visual interface for mapping data fields between pipeline stages, with schemas derived from the component registry.

### Concept

Instead of manually typing `{{upstream.classify.result.category}}`, users can visually drag-and-drop connections between output fields of one stage and input fields of another. The component registry provides the schema definitions for each component's inputs and outputs.

### Current State

```json
{
  "id": "route-ticket",
  "component_type": "router",
  "config": {
    "value": "{{upstream.classify.result.priority}}",
    "conditions": [...]
  }
}
```

Users must:
1. Know the exact path to reference upstream data
2. Manually type template expressions
3. Hope they got the field names right (no validation until runtime)

### Visual Mapping Interface

```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Pipeline Editor: customer-triage                                            │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────────────┐         ┌─────────────────────────┐           │
│  │ 📥 classify             │         │ 🔀 route-ticket         │           │
│  │ generator               │         │ router                  │           │
│  ├─────────────────────────┤         ├─────────────────────────┤           │
│  │ Inputs:                 │         │ Inputs:                 │           │
│  │ ┌─────────────────────┐ │         │ ┌─────────────────────┐ │           │
│  │ │ ○ prompt      string│ │         │ │ ● value      string│◀──┐        │
│  │ │ ○ model       string│ │         │ │ ○ conditions  array│ │  │        │
│  │ └─────────────────────┘ │         │ └─────────────────────┘ │  │        │
│  ├─────────────────────────┤         ├─────────────────────────┤  │        │
│  │ Outputs:                │         │ Outputs:                │  │        │
│  │ ┌─────────────────────┐ │         │ ┌─────────────────────┐ │  │        │
│  │ │ ● category   string│──────┐    │ │ ○ route      string│ │  │        │
│  │ │ ● priority   string│──────┼────┼▶│ ○ matched    bool  │ │  │        │
│  │ │ ● confidence number│──┐   │    │ └─────────────────────┘ │  │        │
│  │ │ ● sentiment  string│  │   │    └─────────────────────────┘  │        │
│  │ └─────────────────────┘ │  │   │                               │        │
│  └─────────────────────────┘  │   │  ┌─────────────────────────┐  │        │
│                               │   │  │ 📊 create-summary       │  │        │
│                               │   │  │ json_transform          │  │        │
│                               │   │  ├─────────────────────────┤  │        │
│                               │   │  │ Inputs:                 │  │        │
│                               │   │  │ ┌─────────────────────┐ │  │        │
│                               │   └──┼▶│ ● category   string│ │  │        │
│                               └──────┼▶│ ● confidence number│ │  │        │
│                                      │ │ ○ threshold  number│ │  │        │
│                                      │ └─────────────────────┘ │  │        │
│                                      └─────────────────────────┘  │        │
│                                                                    │        │
│  ┌─ Legend ───────────────────────────────────────────────────────┘        │
│  │ ● = Connected   ○ = Unconnected   ─▶ = Data flow                        │
│  └──────────────────────────────────────────────────────────────────────────│
└─────────────────────────────────────────────────────────────────────────────┘
```

### Field Mapping Panel

When clicking on a connection or an input field:

```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Field Mapping: route-ticket.value                                    [✕]    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Target Field                          Source                               │
│  ┌───────────────────────┐            ┌───────────────────────────────────┐│
│  │ value                 │     ◀───   │ ○ Input                           ││
│  │ type: string          │            │   ├─ message                      ││
│  │ required: true        │            │   └─ customer_id                  ││
│  │                       │            │                                   ││
│  │ Current mapping:      │            │ ● Upstream Stages                 ││
│  │ {{upstream.classify   │            │   └─ classify                     ││
│  │   .result.priority}}  │            │       ├─ ● category    ← selected ││
│  │                       │            │       ├─ ● priority               ││
│  │                       │            │       ├─ ○ confidence             ││
│  │                       │            │       └─ ○ sentiment              ││
│  │                       │            │                                   ││
│  │                       │            │ ○ Context Variables               ││
│  │                       │            │   ├─ run_id                       ││
│  │                       │            │   └─ timestamp                    ││
│  │                       │            │                                   ││
│  │                       │            │ ○ Pipeline Variables              ││
│  │                       │            │   └─ active_user_count            ││
│  └───────────────────────┘            └───────────────────────────────────┘│
│                                                                             │
│  Transform (optional):                                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ ○ Direct mapping (no transform)                                     │   │
│  │ ○ JMESPath expression: [________________]                           │   │
│  │ ○ Template expression: [________________]                           │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  Preview:                                                                   │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ Source value: "high"                                                │   │
│  │ Mapped value: "high"                                                │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│                                              [Cancel]  [Apply Mapping]      │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Registry-Driven Schemas

Component schemas come from the `@operator` decorator in the registry:

```python
# lab/flowmason_lab/operators/core/generator.py
@operator(
    name="generator",
    category="ai",
    input_schema={
        "type": "object",
        "properties": {
            "prompt": {"type": "string", "description": "The prompt template"},
            "model": {"type": "string", "default": "claude-3-haiku"},
            "temperature": {"type": "number", "default": 0.7},
            "max_tokens": {"type": "integer", "default": 1024}
        },
        "required": ["prompt"]
    },
    output_schema={
        "type": "object",
        "properties": {
            "result": {
                "type": "object",
                "description": "Parsed JSON response from LLM",
                "additionalProperties": True
            },
            "raw_text": {"type": "string"},
            "tokens_used": {"type": "integer"},
            "model": {"type": "string"}
        }
    }
)
class GeneratorOperator(Operator):
    ...
```

### Schema Inference

For dynamic outputs (like `generator` that returns parsed JSON), the system can:

1. **Use explicit schema hints** in the pipeline:
```json
{
  "id": "classify",
  "component_type": "generator",
  "config": { ... },
  "output_hints": {
    "result": {
      "type": "object",
      "properties": {
        "category": {"type": "string"},
        "priority": {"type": "string", "enum": ["low", "medium", "high"]},
        "confidence": {"type": "number"}
      }
    }
  }
}
```

2. **Learn from execution history**:
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 💡 Schema learned from last 10 executions of "classify" stage:              │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  result: {                                                                  │
│    category: string     (seen: "billing", "technical", "sales")            │
│    priority: string     (seen: "low", "medium", "high")                    │
│    confidence: number   (range: 0.75 - 0.98)                               │
│    sentiment: string    (seen: "positive", "negative", "neutral")          │
│  }                                                                          │
│                                                                             │
│  [Save as Schema Hint]  [Ignore]                                           │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Complex Mapping Scenarios

#### Array Mapping (foreach context)
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Inside foreach: process-items                                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Available Sources:                                                         │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ 📍 Loop Context (current iteration)                                 │   │
│  │    ├─ current_item: object                                          │   │
│  │    │   ├─ id: string                                                │   │
│  │    │   ├─ name: string                                              │   │
│  │    │   └─ value: number                                             │   │
│  │    ├─ item_index: number                                            │   │
│  │    └─ total_items: number                                           │   │
│  │                                                                     │   │
│  │ 📦 Upstream (before loop)                                           │   │
│  │    └─ fetch-items.result: array                                     │   │
│  │                                                                     │   │
│  │ 📥 Pipeline Input                                                   │   │
│  │    └─ threshold: number                                             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘
```

#### Object Spread / Multiple Fields
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Multi-Field Mapping: create-summary.data                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  Target: data (object)                                                      │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │ {                                                                   │   │
│  │   "classification": ← classify.result                              │   │
│  │   "items": ← process-items.results                                 │   │
│  │   "count": ← process-items.total_iterations                        │   │
│  │   "threshold": ← input.threshold                                   │   │
│  │ }                                                                   │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  Mapping Mode:                                                              │
│  ● Build object from multiple sources                                      │
│  ○ Map single value                                                        │
│  ○ Spread upstream result                                                  │
│                                                                             │
│  [+ Add Field]                                          [Apply]            │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Visual Validation

Real-time validation as you map:

```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Mapping Validation                                                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ✅ route-ticket.value ← classify.result.priority                          │
│     string → string (compatible)                                           │
│                                                                             │
│  ⚠️ filter-items.threshold ← classify.result.confidence                    │
│     number expected, but source is sometimes string                        │
│     Suggestion: Add type coercion or validate upstream                     │
│                                                                             │
│  ❌ notify.recipient ← (unmapped)                                          │
│     Required field has no mapping                                          │
│                                                                             │
│  ℹ️ create-summary.optional_note ← (unmapped)                              │
│     Optional field, will use default value                                 │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Implementation

#### Registry Schema Enhancement

```python
# core/flowmason_core/registry/types.py
@dataclass
class OperatorSchema:
    input_schema: Dict[str, Any]      # JSON Schema for inputs
    output_schema: Dict[str, Any]     # JSON Schema for outputs
    config_schema: Dict[str, Any]     # JSON Schema for config

@dataclass
class RegisteredOperator:
    name: str
    operator_class: Type[Operator]
    schema: OperatorSchema
    metadata: OperatorMetadata
```

#### API for Schema Discovery

```python
# GET /api/v1/registry/{component_type}/schema
{
  "component_type": "generator",
  "input_schema": {
    "type": "object",
    "properties": {
      "prompt": {"type": "string"},
      "model": {"type": "string"}
    }
  },
  "output_schema": {
    "type": "object",
    "properties": {
      "result": {"type": "object"},
      "raw_text": {"type": "string"}
    }
  }
}

# GET /api/v1/pipelines/{pipeline}/stages/{stage}/inferred-schema
{
  "stage_id": "classify",
  "output_schema": {
    "type": "object",
    "properties": {
      "category": {"type": "string", "observed_values": ["billing", "technical"]},
      "priority": {"type": "string", "observed_values": ["low", "medium", "high"]}
    }
  },
  "sample_count": 47,
  "last_updated": "2025-12-13T10:30:00Z"
}
```

#### Frontend Components

```typescript
// studio/frontend/src/components/mapping/
├── FieldMapper.tsx           // Main mapping interface
├── SchemaTree.tsx            // Tree view of available fields
├── ConnectionLine.tsx        // SVG line between nodes
├── MappingPanel.tsx          // Detail panel for a mapping
├── TypeBadge.tsx             // Shows field type with color
└── ValidationIndicator.tsx   // Shows mapping validation status

// Key interfaces
interface FieldMapping {
  targetStageId: string;
  targetField: string;
  sourceExpression: string;  // Template expression
  sourceType: 'upstream' | 'input' | 'context' | 'variable';
  sourceStageId?: string;
  sourceField?: string;
  transform?: string;  // Optional JMESPath
}

interface StageSchema {
  stageId: string;
  componentType: string;
  inputs: JSONSchema;
  outputs: JSONSchema;
  inferredOutputs?: JSONSchema;  // From execution history
}
```

#### DAG Canvas Integration

```typescript
// Extend existing DAG canvas
interface NodeWithPorts extends PipelineNode {
  inputPorts: Port[];   // Derived from schema
  outputPorts: Port[];  // Derived from schema
}

interface Port {
  id: string;
  name: string;
  type: string;
  required: boolean;
  connected: boolean;
  position: { x: number; y: number };
}

// Connection is a visual line + underlying mapping
interface Connection {
  id: string;
  sourceNodeId: string;
  sourcePortId: string;
  targetNodeId: string;
  targetPortId: string;
  mapping: FieldMapping;
}
```

### User Flow

1. **Add a stage** → Component schema loaded from registry
2. **Expand stage** → See input/output ports with types
3. **Drag from output port** → Line follows cursor
4. **Drop on input port** → Mapping created (if types compatible)
5. **Click connection** → Open mapping panel for transforms
6. **Save pipeline** → Mappings converted to template expressions

### Generated Pipeline JSON

Visual mappings are stored as standard template expressions:

```json
{
  "id": "route-ticket",
  "component_type": "router",
  "config": {
    "value": "{{upstream.classify.result.priority}}"
  },
  "_visual_mappings": [
    {
      "target": "config.value",
      "source": {
        "stage": "classify",
        "path": "result.priority"
      }
    }
  ]
}
```

The `_visual_mappings` metadata is optional and used only by the visual editor to reconstruct the view.

---

## Notes

- Document created: 2025-12-13
- Last updated: 2025-12-13
- Features 12-22 added: 2025-12-13
- Feature 23 (Code Generation) added: 2025-12-13
- Feature 24 (Visual Field Mapping) added: 2025-12-13


---

## 00-status/implementation-status.md

# FlowMason Implementation Status

**Last Updated:** December 13, 2025
**Current Version:** 0.5.1

## Executive Summary

FlowMason is approximately **85% complete** as a production-ready AI pipeline orchestration platform. The core framework, execution engine, and VSCode extension are functional. Security hardening and advanced features remain.

## Component Status Overview

| Component | Status | Completion | Notes |
|-----------|--------|------------|-------|
| **Core Framework** | Production-Ready | 95% | All decorators, execution, control flow |
| **Studio Backend** | Functional | 85% | API complete, auth needs hardening |
| **VSCode Extension** | Substantial | 75% | All providers, DAP, test explorer |
| **Multi-Tenancy** | Complete | 100% | org_id on all resources |
| **Documentation** | Substantial | 85% | 22+ doc files |
| **Authentication** | Needs Hardening | 70% | API keys work, SSO basic |

---

## Detailed Status by Component

### 1. Core Framework (`core/flowmason_core/`)

#### Decorators - COMPLETE

| Decorator | Status | Features |
|-----------|--------|----------|
| `@node` | Complete | AI components, LLM integration, timeout (60s), retries (3) |
| `@operator` | Complete | Non-AI utilities, deterministic, timeout (30s) |
| `@control_flow` | Complete | 6 types: conditional, router, foreach, trycatch, subpipeline, return |

#### Execution Engine - COMPLETE

| Feature | Status | Implementation |
|---------|--------|----------------|
| Timeout Enforcement | Working | `asyncio.wait_for()` with 3-level resolution |
| Retry Logic | Integrated | Exponential backoff, jitter, configurable |
| Cancellation Tokens | Working | Task tracking, async callbacks |
| Parallel Execution | Working | Wave-based, semaphore control, max_concurrency=10 |
| Control Flow Handler | Complete | All 6 directive types processed |
| Loop Variable Injection | Working | `{{context.item_variable}}` in foreach |
| Nested Result Propagation | Working | Try/catch stage results accessible downstream |

#### CLI Commands - COMPLETE (12 commands)

```
fm run              # Execute pipeline from file
fm validate         # Validate pipeline files
fm init             # Initialize new FlowMason project
fm deploy           # Deploy pipelines to org
fm pull             # Pull pipelines from org
fm pack             # Build .fmpkg package
fm install          # Install .fmpkg package
fm uninstall        # Remove installed package
fm list             # List installed packages
fm studio           # start/stop/status/restart
fm org              # login/logout/list/default/display
fm auth             # API key management
```

#### Project Structure - COMPLETE

| File | Purpose | Status |
|------|---------|--------|
| `flowmason.json` | Project manifest | Defined & working |
| `.pipeline.json` | Pipeline definitions | Working |
| `.fmpkg` | Package format | Working |

---

### 2. Studio Backend (`studio/flowmason_studio/`)

#### API Routes - COMPLETE

| Route Module | Endpoints | Status |
|--------------|-----------|--------|
| `/api/v1/registry` | Components, packages | Working |
| `/api/v1/pipelines` | CRUD, clone, publish | Working |
| `/api/v1/runs` | Create, status, control | Working |
| `/api/v1/run` | Named pipeline invocation | Working |
| `/api/v1/auth` | API keys, SSO/SAML | Working |
| `/api/v1/allowlist` | Output destination security | Working |
| `/api/v1/connections` | Stored DB/MQ connections | Working |
| `/api/v1/deliveries` | Output delivery logs | Working |
| `/api/v1/ws` | WebSocket for real-time | Working |

#### Input/Output Architecture - COMPLETE

| Feature | Status | Notes |
|---------|--------|-------|
| Named Pipeline Invocation | Working | POST /run with name@version |
| Output Destinations | Working | Webhook, Email, Database, MQ |
| Allowlist Security | Working | Per-org URL/domain approval |
| Stored Connections | Working | Secure credential storage |
| Delivery Logging | Working | Track all output deliveries |
| OutputRouterOperator | Working | In-pipeline routing |
| ErrorRouterOperator | Working | Error notification |

#### Authentication - FUNCTIONAL (Needs Hardening)

| Feature | Status | Notes |
|---------|--------|-------|
| API Keys | Complete | Scoped permissions, audit logging |
| RBAC | Complete | Admin, developer, viewer roles |
| SSO/SAML | Basic | SP implementation, needs signature verification |
| Password Auth | Basic | SHA-256, needs bcrypt |
| Rate Limiting | Basic | In-memory, needs Redis |
| JWT Sessions | Not Started | Currently stateless API keys |

#### Database - COMPLETE

| Feature | Status |
|---------|--------|
| SQLite (dev) | Working |
| PostgreSQL (prod) | Supported via DATABASE_URL |
| Multi-tenancy | org_id on all tables |
| Audit logging | Complete |

---

### 3. VSCode Extension (`vscode-extension/`)

**Current Version:** 0.4.0

#### Language Support - COMPLETE

| Provider | Status | Features |
|----------|--------|----------|
| CompletionProvider | Working | Decorators, components, configs |
| HoverProvider | Working | Documentation on hover |
| DiagnosticsProvider | Working | Real-time validation |
| CodeLensProvider | Working | Run/Preview buttons |
| DefinitionProvider | Working | Go to Definition (F12) |
| DocumentSymbolProvider | Working | Outline view support |
| CodeActionProvider | Working | Quick fixes |

#### Custom Editor (DAG Canvas) - WORKING

| Feature | Status | Notes |
|---------|--------|-------|
| Visual DAG rendering | Working | SVG-based |
| Stage selection | Working | Click to select |
| Connection visualization | Working | Dependency arrows |
| Drag-and-drop | Basic | Stage repositioning |

#### Debug Adapter (DAP) - WORKING

| Feature | Status | Notes |
|---------|--------|-------|
| Breakpoints | Working | F9 to toggle |
| Step Over | Working | F10 |
| Step Into | Working | F11 for sub-pipelines |
| Continue | Working | F5 |
| Variables Panel | Working | Input/output inspection |
| Exception Breakpoints | Working | Break on errors |

#### Test Controller - WORKING

| Feature | Status | Notes |
|---------|--------|-------|
| Test Discovery | Working | Auto-discover .test.json |
| Test Running | Working | Execute via Test Explorer |
| Test Results | Working | Pass/fail display |
| Coverage Reporting | Working | Coverage percentages |

#### Prompt Editor - PARTIAL

| Feature | Status | Notes |
|---------|--------|-------|
| View Prompts | Working | See system/user prompts |
| Edit Prompts | Working | Modify during debug |
| Re-run Stage | Working | Execute with new prompt |
| Side-by-side Compare | Working | Compare outputs |
| Token Streaming | Working | Watch tokens arrive |

#### Commands Registered - 28 total

```
flowmason.startStudio
flowmason.stopStudio
flowmason.restartStudio
flowmason.runPipeline
flowmason.debugPipeline
flowmason.validatePipeline
flowmason.openDagCanvas
flowmason.addStage
flowmason.toggleBreakpoint
flowmason.stepOver
flowmason.continue
flowmason.stopDebugging
flowmason.runTests
flowmason.runTestFile
flowmason.previewComponent
flowmason.newNode
flowmason.newOperator
flowmason.newPipeline
flowmason.showStageConfig
flowmason.refreshComponents
flowmason.refreshPipelines
flowmason.openSettings
flowmason.showOutput
flowmason.clearOutput
flowmason.deployPipeline
flowmason.pullPipeline
flowmason.packProject
flowmason.installPackage
```

---

## What's Remaining

### HIGH PRIORITY (Security Hardening)

| Task | Effort | Impact | Status |
|------|--------|--------|--------|
| JWT/Session Management | 8 hours | Proper auth tokens | Not Started |
| Password Security (bcrypt) | 2 hours | Secure passwords | Not Started |
| SAML Signature Verification | 6 hours | SSO security | Not Started |
| Distributed Rate Limiting (Redis) | 4 hours | Production scaling | Not Started |

### MEDIUM PRIORITY (Feature Gaps)

| Task | Effort | Impact | Status |
|------|--------|--------|--------|
| Export @control_flow in public API | 1 hour | Developer experience | Not Started |
| Conditional breakpoints in DAP | 4 hours | Better debugging | Not Started |
| Watch expressions in debugger | 4 hours | Debugging UX | Not Started |
| SAML Single Logout (SLO) | 4 hours | Complete SSO | Not Started |
| Password reset flow | 4 hours | User management | Not Started |

### LOW PRIORITY (Polish)

| Task | Effort | Impact | Status |
|------|--------|--------|--------|
| React-based stage editor | 20+ hours | Richer visual editing | Optional |
| Private package registry | 20+ hours | Component marketplace | Optional |
| Coverage gutters in editor | 4 hours | Visual feedback | Optional |
| Diff highlighting in prompts | 4 hours | Better UX | Optional |

---

## Architecture Diagram

```
┌─────────────────────────────────────────────────────────────────────┐
│                         VSCode Extension                            │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │
│  │   Language   │  │    Debug     │  │    Test      │              │
│  │   Providers  │  │   Adapter    │  │  Controller  │              │
│  │  (Complete)  │  │   (DAP)      │  │  (Working)   │              │
│  └──────┬───────┘  └──────┬───────┘  └──────┬───────┘              │
│         └──────────────────┼─────────────────┘                      │
│                            │                                        │
│                    ┌───────▼───────┐                                │
│                    │   Extension   │                                │
│                    │     Host      │                                │
│                    └───────┬───────┘                                │
└────────────────────────────┼────────────────────────────────────────┘
                             │ HTTP/WebSocket
                     ┌───────▼───────┐
                     │    Studio     │
                     │   Backend     │
                     │   (FastAPI)   │
                     └───────┬───────┘
                             │
           ┌─────────────────┼─────────────────┐
           │                 │                 │
     ┌─────▼─────┐     ┌─────▼─────┐     ┌─────▼─────┐
     │ Component │     │ Execution │     │    LLM    │
     │  Registry │     │  Engine   │     │ Providers │
     └───────────┘     └───────────┘     └───────────┘
```

---

## File Structure

```
flowmason/
├── core/flowmason_core/           # Core framework (Python)
│   ├── cli/                       # CLI commands
│   ├── core/                      # Decorators, types
│   ├── execution/                 # Executors, control flow
│   ├── registry/                  # Component registry
│   ├── project/                   # Project manifest
│   └── packaging/                 # .fmpkg builder
├── studio/flowmason_studio/       # Backend server (FastAPI)
│   ├── api/                       # REST routes
│   ├── auth/                      # Authentication
│   ├── services/                  # Business logic
│   └── models/                    # Data models
├── lab/flowmason_lab/             # Built-in components
│   ├── nodes/                     # AI nodes
│   └── operators/                 # Utility operators
├── vscode-extension/              # VSCode extension (TypeScript)
│   ├── src/
│   │   ├── commands/              # Command handlers
│   │   ├── providers/             # Language providers
│   │   ├── debug/                 # DAP implementation
│   │   ├── testing/               # Test controller
│   │   ├── editors/               # Custom editors
│   │   └── views/                 # Tree views
│   └── package.json               # Extension manifest
└── fmdocs/                        # Documentation
```

---

## Version History

| Version | Date | Highlights |
|---------|------|------------|
| 0.1.0 | Nov 2025 | Initial framework, basic execution |
| 0.2.0 | Dec 2025 | CLI, project structure, packaging |
| 0.3.0 | Dec 2025 | Multi-tenancy, API keys, audit logging |
| 0.4.0 | Dec 2025 | SSO/SAML, full DAP, test coverage, documentation |
| 0.5.0 | Dec 2025 | Input/Output Architecture: named pipelines, output routing, allowlists |
| 0.5.1 | Dec 2025 | Control flow handling: foreach loop variables, trycatch nested result propagation |

---

## Next Steps

1. **Security Hardening** - JWT, bcrypt, SAML signatures, Redis rate limiting
2. **Advanced Debugging** - Conditional breakpoints, watch expressions
3. **Enterprise Features** - Private registry, advanced SSO
4. **Polish** - Coverage gutters, prompt diff highlighting


---

## 00-status/remaining-work.md

# Remaining Work

**Last Updated:** December 13, 2025

This document tracks all remaining work items for FlowMason, organized by priority and category.

---

## High Priority: Security Hardening

These items are required before production deployment with sensitive data.

### 1. JWT/Session Management

**Current State:** API keys are stateless tokens stored in database
**Target State:** JWT tokens with refresh flow, session management

**Files to Modify:**
- `studio/flowmason_studio/auth/service.py` - Add JWT generation/validation
- `studio/flowmason_studio/auth/middleware.py` - Add JWT authentication
- `studio/flowmason_studio/auth/models.py` - Add RefreshToken model

**Implementation:**
```python
# Example JWT implementation
import jwt
from datetime import datetime, timedelta

def generate_tokens(user_id: str, org_id: str) -> dict:
    access_token = jwt.encode({
        "sub": user_id,
        "org_id": org_id,
        "exp": datetime.utcnow() + timedelta(hours=1),
        "type": "access"
    }, SECRET_KEY, algorithm="HS256")

    refresh_token = jwt.encode({
        "sub": user_id,
        "exp": datetime.utcnow() + timedelta(days=30),
        "type": "refresh"
    }, SECRET_KEY, algorithm="HS256")

    return {"access_token": access_token, "refresh_token": refresh_token}
```

**Effort:** 8 hours

---

### 2. Password Security (bcrypt)

**Current State:** SHA-256 hash with user ID as salt
**Target State:** bcrypt with proper salt rounds

**File to Modify:** `studio/flowmason_studio/auth/models.py`

**Current Code:**
```python
def set_password(self, password: str) -> None:
    # Simple hash for now - use bcrypt in production
    self.password_hash = hashlib.sha256(
        (password + self.id).encode()
    ).hexdigest()
```

**Target Code:**
```python
import bcrypt

def set_password(self, password: str) -> None:
    salt = bcrypt.gensalt(rounds=12)
    self.password_hash = bcrypt.hashpw(password.encode(), salt).decode()

def verify_password(self, password: str) -> bool:
    return bcrypt.checkpw(password.encode(), self.password_hash.encode())
```

**Effort:** 2 hours

---

### 3. SAML Signature Verification

**Current State:** SAML assertions accepted without signature verification
**Target State:** Verify signatures using IdP certificate

**File to Modify:** `studio/flowmason_studio/auth/saml.py`

**Implementation:**
```python
from signxml import XMLVerifier

def verify_saml_response(response_xml: str, idp_cert: str) -> dict:
    # Parse SAML response
    root = etree.fromstring(response_xml)

    # Verify signature
    verifier = XMLVerifier()
    verified_data = verifier.verify(root, x509_cert=idp_cert)

    # Extract assertion
    assertion = root.find('.//{urn:oasis:names:tc:SAML:2.0:assertion}Assertion')
    return parse_assertion(assertion)
```

**Dependencies:** `signxml` library

**Effort:** 6 hours

---

### 4. Distributed Rate Limiting (Redis)

**Current State:** In-memory rate limiting (single instance only)
**Target State:** Redis-backed rate limiting for multi-instance deployment

**File to Modify:** `studio/flowmason_studio/auth/middleware.py`

**Current Code:**
```python
class RateLimiter:
    def __init__(self):
        self._requests: dict[str, list[float]] = {}  # In-memory
```

**Target Code:**
```python
import redis

class RedisRateLimiter:
    def __init__(self, redis_url: str):
        self.redis = redis.from_url(redis_url)

    async def check_rate_limit(self, key: str, limit: int, window: int) -> bool:
        pipe = self.redis.pipeline()
        now = time.time()
        window_start = now - window

        pipe.zremrangebyscore(key, 0, window_start)
        pipe.zadd(key, {str(now): now})
        pipe.zcard(key)
        pipe.expire(key, window)

        results = pipe.execute()
        return results[2] <= limit
```

**Dependencies:** `redis` library

**Effort:** 4 hours

---

## Medium Priority: Feature Gaps

### 5. Export @control_flow in Public API

**Current State:** @control_flow decorator not exported from `flowmason_core`
**Target State:** Available via `from flowmason_core import control_flow`

**File to Modify:** `core/flowmason_core/__init__.py`

**Change:**
```python
from flowmason_core.core.decorators import node, operator, control_flow

__all__ = [
    "node",
    "operator",
    "control_flow",  # Add this
    # ... rest
]
```

**Effort:** 1 hour

---

### 6. Conditional Breakpoints in DAP

**Current State:** Breakpoints always trigger
**Target State:** Breakpoints can have conditions that evaluate against stage context

**Files to Modify:**
- `vscode-extension/src/debug/flowmasonDebugSession.ts`
- `studio/flowmason_studio/services/execution_controller.py`

**Implementation:**
```typescript
// In debug adapter
setBreakpointsRequest(response, args) {
    const breakpoints = args.breakpoints.map(bp => ({
        stageId: this.lineToStageId(bp.line),
        condition: bp.condition,  // e.g., "{{fetch.output.status}} != 200"
        verified: true
    }));
}
```

**Effort:** 4 hours

---

### 7. Watch Expressions in Debugger

**Current State:** Only stage inputs/outputs visible
**Target State:** Custom expressions evaluated against execution context

**Files to Modify:**
- `vscode-extension/src/debug/flowmasonDebugSession.ts`
- `studio/flowmason_studio/api/routes/debug.py`

**Implementation:**
```typescript
evaluateRequest(response, args) {
    const result = await this.flowmasonService.evaluateExpression(
        this.currentRunId,
        args.expression  // e.g., "{{fetch.output.body.items.length}}"
    );
    response.body = { result: result.value, variablesReference: 0 };
}
```

**Effort:** 4 hours

---

### 8. SAML Single Logout (SLO)

**Current State:** No logout propagation to IdP
**Target State:** SLO request sent to IdP on logout

**Files to Modify:**
- `studio/flowmason_studio/auth/saml.py`
- `studio/flowmason_studio/api/routes/auth.py`

**Effort:** 4 hours

---

### 9. Password Reset Flow

**Current State:** No password reset
**Target State:** Email-based password reset with token

**Files to Create:**
- `studio/flowmason_studio/auth/password_reset.py`
- `studio/flowmason_studio/services/email.py`

**Effort:** 4 hours

---

## Low Priority: Polish & Enhancements

### 10. React-Based Stage Editor

**Current State:** SVG-based DAG canvas
**Target State:** Full React editor with drag-and-drop, node configuration

**Note:** Current SVG editor is functional. React would add richer interactions but requires significant effort.

**Effort:** 20+ hours

---

### 11. Private Package Registry

**Current State:** Local package installation only
**Target State:** Push/pull packages from private registry

**Effort:** 20+ hours

---

### 12. Coverage Gutters in Editor

**Current State:** Coverage shown in Test Explorer
**Target State:** Line-by-line coverage highlighting in editor

**Effort:** 4 hours

---

### 13. Diff Highlighting in Prompt Comparison

**Current State:** Side-by-side text comparison
**Target State:** Character-level diff highlighting

**Effort:** 4 hours

---

## Summary Table

| # | Task | Priority | Effort | Category |
|---|------|----------|--------|----------|
| 1 | JWT/Session Management | HIGH | 8h | Security |
| 2 | Password Security (bcrypt) | HIGH | 2h | Security |
| 3 | SAML Signature Verification | HIGH | 6h | Security |
| 4 | Redis Rate Limiting | HIGH | 4h | Security |
| 5 | Export @control_flow | MEDIUM | 1h | API |
| 6 | Conditional Breakpoints | MEDIUM | 4h | Debugging |
| 7 | Watch Expressions | MEDIUM | 4h | Debugging |
| 8 | SAML Single Logout | MEDIUM | 4h | Auth |
| 9 | Password Reset | MEDIUM | 4h | Auth |
| 10 | React Stage Editor | LOW | 20h+ | UX |
| 11 | Private Registry | LOW | 20h+ | Feature |
| 12 | Coverage Gutters | LOW | 4h | UX |
| 13 | Prompt Diff Highlighting | LOW | 4h | UX |

**Total Remaining (excluding low priority):** ~37 hours


---

## 01-vision/edition-tiers.md

# FlowMason Edition Tiers

## Feature Matrix

| Feature | Basic | Advanced | Enterprise |
|---------|:-----:|:--------:|:----------:|
| **Core** |||||
| Pipeline Builder | ✓ | ✓ | ✓ |
| Component Development | ✓ | ✓ | ✓ |
| Local Execution | ✓ | ✓ | ✓ |
| Basic Debugging | ✓ | ✓ | ✓ |
| .fmpkg Export | ✓ | ✓ | ✓ |
| **Advanced** |||||
| Deep Debugging (Prompts) | - | ✓ | ✓ |
| Prompt Versioning | - | ✓ | ✓ |
| Test Explorer | - | ✓ | ✓ |
| Coverage Reports | - | ✓ | ✓ |
| CI/CD Integration | - | ✓ | ✓ |
| **Enterprise** |||||
| Team Collaboration | - | - | ✓ |
| Remote Execution | - | - | ✓ |
| Private Registry | - | - | ✓ |
| SSO/SAML | - | - | ✓ |
| Audit Logs | - | - | ✓ |
| Role-Based Access | - | - | ✓ |
| Priority Support | - | - | ✓ |
| Custom Integrations | - | - | ✓ |

## Edition Details

### Basic (Free, Open Source)

**License:** Apache 2.0

**Included:**
- Full Pipeline Builder (VSCode or browser)
- All built-in components (nodes, operators, control flow)
- Local pipeline execution
- Basic debugging (breakpoints, step-through)
- Package export (.fmpkg)
- VSCode extension with IntelliSense

**Best for:**
- Individual developers
- Learning and experimentation
- Open source projects
- Small teams getting started

### Advanced

**Pricing:** $29/user/month (Indie: $9/user/month)

**Includes everything in Basic, plus:**
- Deep debugging with prompt iteration
- Prompt version history and comparison
- VSCode Test Explorer integration
- Code coverage reporting
- CI/CD pipeline templates
- GitHub Actions integration
- Priority issue resolution

**Best for:**
- Professional developers
- Small to medium teams
- Production deployments
- CI/CD workflows

### Enterprise

**Pricing:** Custom (annual contract)

**Includes everything in Advanced, plus:**
- Team collaboration features
- Remote execution backend
- Private package registry
- SSO/SAML authentication
- Comprehensive audit logging
- Role-based access control (RBAC)
- Custom integrations
- Dedicated support
- SLA guarantees
- On-premise deployment option

**Best for:**
- Large organizations
- Regulated industries
- Multi-team deployments
- Compliance requirements

## Licensing Model

```
Basic:      Free, open source (Apache 2.0)
Advanced:   $29/user/month
            Indie: $9/user/month (< $100k revenue)
Enterprise: Custom pricing, annual contract
```

## FAQ

### What's included in Basic?

Everything you need to build, debug, and deploy pipelines locally. The Basic tier is fully functional for individual developers and small teams.

### What triggers the need for Advanced?

If you need:
- Prompt iteration during debugging
- Test Explorer integration
- CI/CD automation
- Coverage reporting

### When do I need Enterprise?

If you need:
- Team collaboration
- SSO/SAML
- Audit logs for compliance
- Private registries
- Dedicated support


---

## 01-vision/hybrid-model.md

# The Hybrid Model (Salesforce DX-Style)

## Overview

FlowMason uses a **hybrid deployment model** inspired by Salesforce DX:

- **Development**: File-based pipelines (`.pipeline.json`) in VSCode with Git version control
- **Deployment**: Push to staging/production orgs where pipelines run from databases
- **Runtime**: Backend APIs expose pipelines for consumption

**The goal**: Make building AI pipelines feel as natural as building Salesforce applications.

## Architecture Diagram

```
┌─────────────────────────────────────────────────────────────────────┐
│  LOCAL DEVELOPMENT                                                  │
│  ┌──────────────────────────────────────────────────────────────┐  │
│  │  .pipeline.json files (Git repo)                             │  │
│  │  - Source of truth during development                        │  │
│  │  - VSCode Custom Editor for visual editing                   │  │
│  │  - Debug with DAP, prompt iteration                          │  │
│  └──────────────────────────┬───────────────────────────────────┘  │
│                             │                                       │
│            ┌────────────────┴────────────────┐                     │
│            │                                 │                      │
│            ▼                                 ▼                      │
│  ┌─────────────────┐              ┌─────────────────────┐          │
│  │  FILE MODE      │              │  ORG MODE (optional)│          │
│  │  (Default)      │              │                     │          │
│  │  F5 = Run from  │              │  flowmason deploy   │          │
│  │  file directly  │              │  --local            │          │
│  │  Fast iteration │              │  Test DB behavior   │          │
│  └─────────────────┘              └─────────────────────┘          │
└─────────────────────────────────────────────────────────────────────┘
                            │
              ┌─────────────┴─────────────┐
              │                           │
    flowmason deploy            flowmason deploy
    --target staging            --target production
              │                           │
              ▼                           ▼
┌─────────────────────────┐  ┌─────────────────────────┐
│  STAGING ORG            │  │  PRODUCTION ORG         │
│  - PostgreSQL DB        │  │  - PostgreSQL DB        │
│  - Backend API          │  │  - Backend API          │
│  - Pipelines as records │  │  - Pipelines as records │
│  - Full execution       │  │  - Full execution       │
│  - Studio UI (optional) │  │  - Studio UI (optional) │
└─────────────────────────┘  └─────────────────────────┘
```

## Environment Comparison

| Environment | Storage | Execution | Use Case |
|-------------|---------|-----------|----------|
| **Local (File Mode)** | `.pipeline.json` files | Direct from files | Fast development |
| **Local (Org Mode)** | SQLite | From local DB | Test DB behavior |
| **Staging Org** | PostgreSQL | From DB via API | Integration testing |
| **Production Org** | PostgreSQL | From DB via API | Live runtime |

## Like Salesforce DX

| Salesforce DX | FlowMason |
|---------------|-----------|
| `force-app/` directory | `pipelines/` directory |
| `.cls`, `.trigger` files | `.pipeline.json` files |
| `sfdx force:org:login` | `flowmason org:login` |
| `sfdx force:source:push` | `flowmason deploy` |
| `sfdx force:source:pull` | `flowmason pull` |
| Scratch org (dev) | Local backend (file mode) |
| Sandbox (staging) | Staging org |
| Production org | Production org |
| Metadata in org DB | Pipelines in org DB |

## CLI Commands

### Org Management

```bash
# Authorize to an org (like sf org login)
flowmason org:login --alias staging --instance-url https://staging.flowmason.com
flowmason org:login --alias production --instance-url https://prod.flowmason.com

# List authorized orgs
flowmason org:list
# Output:
#   ALIAS       INSTANCE URL                    DEFAULT
#   staging     https://staging.flowmason.com    ✓
#   production  https://prod.flowmason.com

# Set default org
flowmason org:default staging

# View org details
flowmason org:display --target staging

# Logout from org
flowmason org:logout --target staging
```

### Deploy (Local → Org)

```bash
# Deploy all pipelines to default org
flowmason deploy

# Deploy specific pipeline
flowmason deploy pipelines/main.pipeline.json

# Deploy to specific org
flowmason deploy --target production

# Deploy to local DB (test org mode)
flowmason deploy --local

# Preview what would be deployed (dry run)
flowmason deploy --dry-run

# Deploy with validation only (no execution test)
flowmason deploy --check-only
```

### Pull (Org → Local)

```bash
# Pull all pipelines from default org
flowmason pull

# Pull specific pipeline
flowmason pull --pipeline support-triage

# Pull from specific org
flowmason pull --target production

# Preview what would be pulled
flowmason pull --dry-run
```

### Local Execution (File Mode)

```bash
# Run pipeline from file (no deploy needed)
flowmason run pipelines/main.pipeline.json

# Run with input
flowmason run pipelines/main.pipeline.json --input '{"url": "https://..."}'

# Run with input file
flowmason run pipelines/main.pipeline.json --input-file test-input.json

# Debug mode (starts debug server, VSCode connects)
flowmason run pipelines/main.pipeline.json --debug
```

### Org Execution (From Deployed Pipelines)

```bash
# Run on org (must be deployed first)
flowmason run --target staging --pipeline main
```

### Component Management

```bash
# Package components
flowmason pack --output my-components-1.0.0.fmpkg

# Install package locally
flowmason install my-components-1.0.0.fmpkg

# Deploy package to org
flowmason deploy:package my-components-1.0.0.fmpkg --target staging

# List components in org
flowmason component:list --target staging
```

## VSCode Integration with Orgs

```
┌──────────────────────────────────────────────────────────────────────┐
│ VSCode                                                               │
├──────────────────────────────────────────────────────────────────────┤
│ FLOWMASON ORGS                      │  main.pipeline.json            │
│ ├─ 🟢 staging (default)             │  ┌────────────────────────┐    │
│ │   ├─ Status: Connected            │  │    [Visual Editor]     │    │
│ │   ├─ Pipelines: 5 deployed        │  │                        │    │
│ │   └─ Last sync: 2 min ago         │  │    [A]──►[B]──►[C]     │    │
│ ├─ 🟡 production                    │  │                        │    │
│ │   ├─ Status: Connected            │  └────────────────────────┘    │
│ │   ├─ Pipelines: 3 deployed        │                                │
│ │   └─ Last sync: 1 hour ago        │  ┌────────────────────────────┐│
│ └─ ⚪ local                         │  │ [▶ Run Local] [Deploy ▼]   ││
│     └─ File mode (no DB)            │  │  ├─ Deploy to staging      ││
│                                     │  │  ├─ Deploy to production   ││
│ LOCAL PIPELINES                     │  │  └─ Deploy to local DB     ││
│ ├─ main.pipeline.json ✎ (modified)  │  └────────────────────────────┘│
│ ├─ etl.pipeline.json ✓ (synced)     │                                │
│ └─ support.pipeline.json ✎          │  Status: Modified locally      │
│                                     │  Last deployed: staging (2 min)│
│ ✎ = Modified locally, not deployed  │                                │
│ ✓ = In sync with default org        │                                │
└─────────────────────────────────────┴────────────────────────────────┘
```

## Deployment Flow

The typical developer workflow:

### 1. DEVELOP (Local, File Mode)

```
┌─────────────────────────────────────────┐
│ Edit .pipeline.json in VSCode           │
│ F5 → Run from file (fast iteration)     │
│ Debug, iterate, test locally            │
└─────────────────────────────────────────┘
```

- Edit pipelines visually in VSCode Custom Editor
- Run directly from files (no deploy needed)
- Fast iteration with hot reload
- Debug with breakpoints

### 2. COMMIT (Git)

```
┌─────────────────────────────────────────┐
│ git add pipelines/                      │
│ git commit -m "Add support pipeline"    │
│ git push                                │
└─────────────────────────────────────────┘
```

- Version control with Git
- Code review via pull requests
- Collaboration with team

### 3. DEPLOY TO STAGING

```
┌─────────────────────────────────────────┐
│ flowmason deploy --target staging       │
│ - Validates pipeline                    │
│ - Converts to DB records                │
│ - Deploys to staging org                │
└─────────────────────────────────────────┘
```

- Validation before deployment
- Conversion from file to database records
- Full integration testing environment

### 4. TEST IN STAGING

```
┌─────────────────────────────────────────┐
│ flowmason run --target staging          │
│   --pipeline support-triage             │
│ - Runs from staging DB                  │
│ - Full production-like behavior         │
└─────────────────────────────────────────┘
```

- Test in production-like environment
- API endpoints available
- Full observability

### 5. DEPLOY TO PRODUCTION

```
┌─────────────────────────────────────────┐
│ flowmason deploy --target production    │
│ - Same pipeline, production org         │
│ - APIs now available for consumers      │
└─────────────────────────────────────────┘
```

- Promote from staging to production
- Same pipeline definition
- Production APIs activated

### 6. CONSUME VIA API

```
┌─────────────────────────────────────────┐
│ POST https://prod.flowmason.com/api/v1/  │
│   pipelines/support-triage/run          │
│ Body: { "input": {...} }                │
└─────────────────────────────────────────┘
```

- REST API for pipeline execution
- WebSocket for real-time updates
- Full metrics and logging

## CI/CD Integration

### GitHub Actions Example

```yaml
# .github/workflows/flowmason.yml
name: FlowMason CI/CD

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup FlowMason
        uses: flowmason/setup-action@v1

      - name: Validate pipelines
        run: flowmason validate pipelines/

      - name: Run tests (file mode)
        run: flowmason test --all

  deploy-staging:
    needs: test
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup FlowMason
        uses: flowmason/setup-action@v1

      - name: Login to staging
        run: flowmason org:login --alias staging --auth-url ${{ secrets.STAGING_AUTH_URL }}

      - name: Deploy to staging
        run: flowmason deploy --target staging

  deploy-production:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Setup FlowMason
        uses: flowmason/setup-action@v1

      - name: Login to production
        run: flowmason org:login --alias production --auth-url ${{ secrets.PROD_AUTH_URL }}

      - name: Deploy to production
        run: flowmason deploy --target production
```

## Why Hybrid?

### Benefits of File-Based Development

- **Git version control** - Track changes, review, rollback
- **Fast iteration** - No deploy needed for local testing
- **IDE integration** - IntelliSense, diagnostics, refactoring
- **Collaboration** - Pull requests, code review
- **Offline work** - No server connection needed

### Benefits of Database Runtime

- **Performance** - Optimized queries, caching
- **API exposure** - REST/WebSocket endpoints
- **Scalability** - Multiple instances, load balancing
- **Observability** - Metrics, logging, tracing
- **Management** - Studio UI for monitoring

### The Best of Both Worlds

FlowMason gives you:
- Developer experience of file-based tools
- Production capabilities of database-backed systems
- Seamless transition between local and deployed


---

## 01-vision/product-vision.md

# FlowMason Product Vision

## Executive Summary

FlowMason is an AI pipeline orchestration platform that enables developers to design, build, debug, and deploy intelligent workflows. The platform uses a **Salesforce DX-style hybrid model**:

- **Development**: File-based pipelines (`.pipeline.json`) in VSCode with Git version control
- **Deployment**: Push to staging/production orgs where pipelines run from databases
- **Runtime**: Backend APIs expose pipelines for consumption

**The goal**: Make building AI pipelines feel as natural as building Salesforce applications.

## The Platform Model

### Environment Overview

| Environment | Storage | Execution | Use Case |
|-------------|---------|-----------|----------|
| **Local (File Mode)** | `.pipeline.json` files | Direct from files | Fast development |
| **Local (Org Mode)** | SQLite | From local DB | Test DB behavior |
| **Staging Org** | PostgreSQL | From DB via API | Integration testing |
| **Production Org** | PostgreSQL | From DB via API | Live runtime |

### Developer Workflow

1. **Develop locally** - Edit `.pipeline.json` files in VSCode, run from files
2. **Version with Git** - Commit, push, create pull requests
3. **Deploy to staging** - `flowmason deploy --target staging`
4. **Test in staging** - Run pipelines via API
5. **Deploy to production** - `flowmason deploy --target production`
6. **Consume via API** - REST/WebSocket endpoints for pipeline execution

See [The Hybrid Model](hybrid-model.md) for complete details on the deployment architecture.

## VSCode-Native Development

### Custom Editor Provider

Pipelines open in a visual canvas editor, not as raw JSON:

- Double-click `.pipeline.json` → Opens visual editor
- Ctrl+S → Saves to file (auto-format)
- Native undo/redo via VSCode
- Multiple pipelines in tabs
- Split view: canvas + JSON

### Debug Adapter Protocol (DAP)

Full debugging experience for pipelines:

**Debug Panel Features:**

| Panel | Contents |
|-------|----------|
| Variables | Current stage inputs, outputs, context |
| Watch | Custom expressions to monitor |
| Call Stack | Pipeline → Stage → Sub-pipeline |
| Breakpoints | List of all breakpoints |
| Prompt Editor | Edit and re-run prompts live |

**Breakpoint Types:**
- Stage breakpoints (pause before stage executes)
- Conditional breakpoints (`input.text.length > 1000`)
- Logpoints (log without pausing)
- Exception breakpoints (pause on error)

### Deep Debugging: Prompt Iteration

The killer feature - edit prompts during debug:

```
┌─────────────────────────────────────────────────────────────────┐
│ Debug: Paused at "summarize-content"                            │
├─────────────────────────┬───────────────────────────────────────┤
│ VARIABLES               │ PROMPT EDITOR                         │
│ ├─ input                │ ┌───────────────────────────────────┐ │
│ │  └─ text: "The q..."  │ │ System:                           │ │
│ │                       │ │ You are a concise summarizer.     │ │
│ ├─ context              │ │                                   │ │
│ │  └─ run_id: "r-123"   │ │ User:                             │ │
│ │                       │ │ Summarize this text in            │ │
│ └─ output: (pending)    │ │ {{max_length}} words or less:     │ │
│                         │ │                                   │ │
├─────────────────────────┤ │ {{text}}                          │ │
│ PROMPT VERSIONS         │ │                                   │ │
│ ├─ v1 (original)        │ └───────────────────────────────────┘ │
│ ├─ v2 (shorter)         │                                       │
│ └─ v3 (current) ●       │ [Edit] [Reset] [Save as v4]           │
└─────────────────────────┴───────────────────────────────────────┘
```

**Workflow:**
1. Pause at LLM stage
2. See the prompt being sent
3. Edit prompt directly
4. Re-run just that stage
5. Compare output to previous versions
6. Save successful prompt as new version
7. Continue execution

### Test Explorer Integration

Native VSCode test UI with:

| Test Type | Description |
|-----------|-------------|
| Unit | Single component with mock input |
| Integration | Component chains |
| Sub-pipeline | Partial DAG testing |
| E2E | Full pipeline execution |
| Regression | Golden file comparison |
| Prompt | A/B testing prompts |

## File-Based Pipelines

### Pipeline File Format (`.pipeline.json`)

```json
{
  "name": "content-pipeline",
  "version": "1.0.0",
  "description": "Process and summarize content",
  "stages": [
    {
      "id": "fetch",
      "component": "http-request",
      "config": {
        "url": "{{input.url}}",
        "method": "GET"
      }
    },
    {
      "id": "summarize",
      "component": "generator",
      "depends_on": ["fetch"],
      "config": {
        "prompt": "Summarize: {{fetch.output.body}}",
        "max_tokens": 500
      }
    }
  ],
  "input_schema": {
    "type": "object",
    "properties": {
      "url": { "type": "string", "format": "uri" }
    },
    "required": ["url"]
  }
}
```

### Project Structure

```
my-flowmason-project/
├── flowmason.json              # Project manifest
├── .flowmason/
│   ├── state.json              # IDE state (tabs, zoom, selection)
│   ├── cache/                  # Registry cache
│   ├── runs/                   # Local execution history
│   └── prompts/                # Prompt version history
├── pipelines/
│   ├── main.pipeline.json
│   └── tests/
│       └── main.test.json
├── components/
│   ├── nodes/
│   └── operators/
└── packages/                   # Built .fmpkg files
```

### Project Manifest (`flowmason.json`)

```json
{
  "name": "my-flowmason-project",
  "version": "1.0.0",
  "description": "My AI pipeline project",
  "main": "pipelines/main.pipeline.json",
  "components": {
    "include": ["components/**/*.py"]
  },
  "providers": {
    "default": "anthropic",
    "anthropic": { "model": "claude-sonnet-4-20250514" }
  },
  "testing": {
    "timeout": 30000,
    "retries": 2
  }
}
```

## Packaging (.fmpkg)

Self-contained deployable units, like Java WAR files:

```
my-workflow-1.0.0.fmpkg
├── manifest.json           # Metadata, version, dependencies
├── pipelines/              # All pipeline definitions
├── components/             # Custom nodes and operators
├── prompts/                # Prompt templates
├── tests/                  # Test definitions
├── config/                 # Environment configs
└── assets/                 # Additional resources
```

### Package Commands

```bash
flowmason pack                    # Build .fmpkg
flowmason pack --version 1.2.0    # Build with version
flowmason install package.fmpkg   # Install locally
flowmason deploy --target staging # Deploy to org
```

## CI/CD Integration

### GitHub Actions

```yaml
name: FlowMason CI/CD
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: flowmason/setup-action@v1
      - run: flowmason test --coverage

  deploy-staging:
    needs: test
    if: github.ref == 'refs/heads/develop'
    steps:
      - run: flowmason deploy --target staging

  deploy-production:
    needs: test
    if: github.ref == 'refs/heads/main'
    steps:
      - run: flowmason deploy --target production
```

## Migration Strategy

### Current State
- Browser-based Pipeline Builder
- Pipelines stored in SQLite database
- VSCode extension opens browser

### Target State
- VSCode-native Pipeline Builder
- Pipelines as `.pipeline.json` files (local) + database (staging/prod)
- Full debugging/testing integration
- Deploy/pull workflow

### Migration Path

1. **Parallel operation** - Keep browser version working during transition
2. **Export tool** - Export existing pipelines from DB to files
3. **Feature parity** - Match browser functionality in VSCode
4. **Deploy/pull commands** - Enable org management
5. **Complete transition** - VSCode becomes primary interface


---

## 01-vision/README.md

# FlowMason Vision

## Overview

FlowMason is an AI pipeline orchestration platform that enables developers to design, build, debug, and deploy intelligent workflows. The platform uses a **Salesforce DX-style hybrid model**:

- **Development**: File-based pipelines (`.pipeline.json`) in VSCode with Git version control
- **Deployment**: Push to staging/production orgs where pipelines run from databases
- **Runtime**: Backend APIs expose pipelines for consumption

**Goal:** Make building AI pipelines feel as natural as building Salesforce applications.

## Documents in This Section

| Document | Description |
|----------|-------------|
| [Hybrid Model](hybrid-model.md) | The Salesforce DX-style deployment architecture |
| [Product Vision](product-vision.md) | Full vision for VSCode-native FlowMason |
| [Roadmap](roadmap.md) | Implementation phases and milestones |
| [Edition Tiers](edition-tiers.md) | Basic, Advanced, Enterprise features |

## The Platform Model

```
LOCAL DEVELOPMENT                    STAGING/PRODUCTION
┌─────────────────────┐             ┌─────────────────────┐
│ .pipeline.json      │  deploy     │ PostgreSQL Database │
│ files (Git repo)    │────────────>│ Backend APIs        │
│ VSCode + Extension  │             │ Runtime Execution   │
└─────────────────────┘             └─────────────────────┘
        │                                    │
   Fast iteration                    Production runtime
   Version control                   API consumption
   Debug & test                      Full observability
```

### Environments

| Environment | Storage | Execution | Use Case |
|-------------|---------|-----------|----------|
| **Local (File Mode)** | `.pipeline.json` files | Direct from files | Fast development |
| **Local (Org Mode)** | SQLite | From local DB | Test DB behavior |
| **Staging Org** | PostgreSQL | From DB via API | Integration testing |
| **Production Org** | PostgreSQL | From DB via API | Live runtime |

## The Problem

Current browser-based pipeline builders suffer from:

| Problem | Impact |
|---------|--------|
| Context switching | Jump between IDE and browser constantly |
| No version control | Pipelines trapped in databases, not Git |
| Limited debugging | Basic logging, no breakpoints |
| No IDE integration | Miss autocomplete, linting, refactoring |
| Collaboration friction | Can't code review pipelines |
| CI/CD gaps | Manual deployment, no automation |
| No deployment model | Local only, no staging/production |

## The Solution

### VSCode-Native Development

Transform VSCode into the FlowMason IDE:

```
┌─────────────────────────────────────────────────────────────────────┐
│  VSCode + FlowMason                                                 │
├──────────┬────────────────────────────────────────┬─────────────────┤
│ Explorer │  main.pipeline.json (Custom Editor)    │  Debug Panel    │
│ ┌──────┐ │  ┌──────────────────────────────────┐  │  ┌───────────┐  │
│ │ src/ │ │  │     [fetch]──►[process]          │  │  │ Variables │  │
│ │ pipe │ │  │        │          │              │  │  │ input: {} │  │
│ │ comp │ │  │        ▼          ▼              │  │  │ output: {}│  │
│ └──────┘ │  │     [clean]──►[summarize]──►[out]│  │  └───────────┘  │
├──────────┤  └──────────────────────────────────┘  │  ┌───────────┐  │
│FlowMason │                                        │  │Breakpoints│  │
│ ┌──────┐ │  ──────────────────────────────────────│  │ ● stage-2 │  │
│ │Comps │ │  Problems │ Output │ Debug Console     │  │ ○ stage-4 │  │
│ │Pipes │ │  [FlowMason] Stage 'process' complete  │  └───────────┘  │
│ │Tests │ │  [FlowMason] Running 'summarize'...    │                 │
│ └──────┘ │                                        │                 │
└──────────┴────────────────────────────────────────┴─────────────────┘
```

### Org-Based Deployment

Deploy pipelines to staging and production environments:

```bash
# Develop locally
flowmason run pipelines/main.pipeline.json

# Deploy to staging
flowmason deploy --target staging

# Test in staging
flowmason run --target staging --pipeline main

# Deploy to production
flowmason deploy --target production
```

## Key Principles

1. **File-based development** - Pipelines are `.pipeline.json` files, Git-friendly
2. **Database-backed runtime** - Staging/production use PostgreSQL for performance
3. **Project-based** - FlowMason projects with manifest, state, history
4. **Native debugging** - VSCode Debug Adapter Protocol (DAP)
5. **Integrated testing** - VSCode Test Explorer for pipeline tests
6. **Packaged deployment** - `.fmpkg` bundles like Java WAR files
7. **CI/CD ready** - GitHub Actions, tasks, automation

## Key Differentiators

| Traditional Tools | FlowMason Vision |
|-------------------|------------------|
| Browser-based builder | VSCode-native custom editor |
| Database storage only | Files (dev) + Database (staging/prod) |
| Console logging | Debug Adapter Protocol (breakpoints, step-through) |
| No testing framework | VSCode Test Explorer integration |
| Manual deployment | `flowmason deploy` with CI/CD |
| No environments | Local → Staging → Production |
| Single user | Team collaboration with enterprise features |


---

## 01-vision/roadmap.md

# FlowMason Roadmap

## Implementation Phases

### Phase 0: Stabilization
**Goal:** Fix critical gaps in core execution engine

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Integrate retry logic into UniversalExecutor | Pending | Logic exists, not wired |
| Integrate cancellation tokens into DAGExecutor | Pending | Token exists, not passed |
| Add timeout enforcement (asyncio.wait_for) | Pending | Metadata exists, not enforced |
| Wire ControlFlowHandler fully | Pending | Handler exists, partial integration |
| Add parallel execution for independent stages | Pending | Currently sequential only |
| Tests for all execution paths | Pending | |

**Why This First:** The core execution engine has several features defined but not integrated. Before building VSCode integration, the foundation must be solid.

---

### Phase 1: Foundation (File-Based Pipelines)
**Goal:** Move from database-stored pipelines to Git-friendly files

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Define `.pipeline.json` file format | Pending | Based on PipelineDetail model |
| Define `flowmason.json` project manifest | Pending | |
| Create `.flowmason/` directory structure | Pending | State, cache, runs, prompts |
| Update Studio backend for file-based pipelines | Pending | |
| Add import/export between SQLite and files | Pending | Migration tool |
| Session state persistence in workspace | Pending | |

**Dependencies:** Phase 0 complete

---

### Phase 2: VSCode Custom Editor
**Goal:** Open .pipeline.json files in visual editor within VSCode

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Implement CustomEditorProvider | Pending | For `.pipeline.json` files |
| Extract Pipeline Builder React code | Pending | For webview embedding |
| Configure Vite build for webview | Pending | |
| Document ↔ Webview sync via postMessage | Pending | |
| Native save (Ctrl+S writes to file) | Pending | |
| Native undo/redo via VSCode | Pending | |
| Multi-tab support | Pending | Multiple pipelines open |

**Dependencies:** Phase 1 complete

---

### Phase 3: Debug Adapter Protocol (DAP)
**Goal:** Native VSCode debugging for pipelines

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Implement DebugAdapterDescriptorFactory | Pending | |
| Map stage breakpoints to DAP breakpoints | Pending | |
| Implement step over (next stage) | Pending | |
| Implement step into (sub-pipeline) | Pending | |
| Variables panel (inputs/outputs/context) | Pending | |
| Call stack (pipeline → stage hierarchy) | Pending | |
| Exception breakpoints (pause on error) | Pending | |
| Integrate with ExecutionController | Pending | Existing controller |

**Dependencies:** Phase 2 complete, ExecutionController exists

---

### Phase 4: Deep Debugging (Prompt Iteration)
**Goal:** Edit prompts during debug, re-run stages

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Prompt editor webview panel | Pending | |
| Capture prompt templates from LLM nodes | Pending | |
| Re-execute single stage with modified prompt | Pending | |
| Prompt version history | Pending | Save successful prompts |
| Side-by-side output comparison | Pending | |
| Token streaming visualization | Pending | |

**Dependencies:** Phase 3 complete

---

### Phase 5: Testing Framework
**Goal:** Native VSCode Test Explorer integration

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Define `.test.json` test file format | Pending | |
| Implement TestController | Pending | For FlowMason tests |
| Unit tests (single component) | Pending | With mock input |
| Integration tests (component chains) | Pending | |
| Pipeline E2E tests | Pending | |
| Golden file regression tests | Pending | |
| Coverage reporting | Pending | |

**Dependencies:** Phase 3 complete

---

### Phase 6: Packaging & CI/CD
**Goal:** Self-contained deployable packages

**Status:** Partial (basic .fmpkg exists)

| Task | Status | Notes |
|------|--------|-------|
| Finalize `.fmpkg` ZIP format | Partial | Format defined |
| CLI: `flowmason pack` command | Pending | |
| CLI: `flowmason deploy` command | Pending | |
| VSCode Task Provider | Pending | For build/test/deploy |
| GitHub Actions workflow templates | Pending | |
| Package dependency resolution | Pending | |

**Dependencies:** Phase 5 complete

---

### Phase 7: Enterprise Features
**Goal:** Team collaboration and compliance

**Status:** Not Started

| Task | Status | Notes |
|------|--------|-------|
| Package registry (publish/install remote) | Pending | |
| Remote execution backend | Pending | |
| SSO/SAML authentication | Pending | |
| Audit logging for executions | Pending | |
| Role-based access control | Pending | |
| Private component registries | Pending | |

**Dependencies:** Phase 6 complete

---

## Current State Summary

| Component | Status |
|-----------|--------|
| Core decorators (@node, @operator, @control_flow) | Complete |
| UniversalExecutor + DAGExecutor | Complete (sequential) |
| 18 built-in components | Complete |
| Studio backend (FastAPI) | Complete |
| Studio frontend (React) | Complete |
| WebSocket real-time updates | Complete |
| ExecutionController (debug) | Complete |
| VSCode extension (basic) | Complete |
| Retry/Cancel/Timeout integration | NOT IMPLEMENTED |
| Parallel execution | NOT IMPLEMENTED |
| File-based pipelines | NOT IMPLEMENTED |
| VSCode Custom Editor | NOT IMPLEMENTED |
| Debug Adapter Protocol | NOT IMPLEMENTED |


---

## 02-getting-started/installation.md

# Installation

This guide covers how to install FlowMason components for development.

## Prerequisites

- Python 3.11+
- Node.js 18+ (for Studio frontend and VSCode extension development)
- VSCode (recommended IDE)

## Installing FlowMason Core

FlowMason Core is the Python framework for building components and executing pipelines.

```bash
# Install from source (development)
cd core
pip install -e ".[all]"

# This installs:
# - flowmason_core - Core framework
# - CLI tools (flowmason, fm commands)
# - All optional dependencies
```

### Core Dependencies

| Package | Purpose |
|---------|---------|
| `pydantic` | Type validation and schemas |
| `typer` | CLI framework |
| `rich` | Terminal formatting |
| `httpx` | HTTP client for API calls |
| `jmespath` | JSON path queries |

## Installing FlowMason Studio

Studio provides the backend API server and optional web UI.

```bash
# Install from source (development)
cd studio
pip install -e .

# Start Studio server
flowmason studio start
# or
fm studio start
```

Studio runs on `http://localhost:8999` by default.

### Studio Dependencies

| Package | Purpose |
|---------|---------|
| `fastapi` | API framework |
| `uvicorn` | ASGI server |
| `websockets` | Real-time updates |
| `sqlalchemy` | Database ORM |

## Installing the VSCode Extension

### From VSIX (Recommended)

```bash
# Install from .vsix file
code --install-extension vscode-extension/flowmason-0.10.0.vsix
```

### From Source

```bash
cd vscode-extension
npm install
npm run compile
npm run package
code --install-extension flowmason-0.10.0.vsix
```

## Verifying Installation

```bash
# Check CLI
fm --version

# Check Studio
fm studio status

# In VSCode, open Command Palette (Cmd+Shift+P)
# Type "FlowMason" to see available commands
```

## Project Setup

Initialize a new FlowMason project:

```bash
# Create project directory
mkdir my-project && cd my-project

# Initialize FlowMason project
fm init

# This creates:
# - flowmason.json (project manifest)
# - pipelines/ directory
# - components/ directory
# - .flowmason/ directory (state)
```

## Environment Variables

| Variable | Purpose | Default |
|----------|---------|---------|
| `FLOWMASON_HOST` | Studio server host | `127.0.0.1` |
| `FLOWMASON_PORT` | Studio server port | `8999` |
| `ANTHROPIC_API_KEY` | Anthropic API key | - |
| `OPENAI_API_KEY` | OpenAI API key | - |

## Database Configuration

Studio uses SQLite by default. For production, configure PostgreSQL:

```python
# Set via environment variable
DATABASE_URL=postgresql://user:pass@host:5432/flowmason
```

Or configure in `flowmason.json`:

```json
{
  "database": {
    "type": "postgresql",
    "url": "postgresql://user:pass@host:5432/flowmason"
  }
}
```

## Next Steps

- [Quick Start](quickstart.md) - Build your first pipeline
- [Core Concepts](../03-concepts/architecture-overview.md) - Understand how FlowMason works
- [VSCode Extension](../07-vscode-extension/overview.md) - Use the VSCode integration


---

## 02-getting-started/quickstart.md

# Quick Start Guide

Build and run your first FlowMason pipeline in 5 minutes.

## Prerequisites

- FlowMason installed ([Installation Guide](installation.md))
- An LLM API key (Anthropic or OpenAI)

## Step 1: Initialize a Project

```bash
mkdir my-first-pipeline && cd my-first-pipeline
fm init
```

This creates:
```
my-first-pipeline/
├── flowmason.json          # Project configuration
├── pipelines/              # Pipeline definitions
├── components/             # Custom components
└── .flowmason/            # State and cache
```

## Step 2: Set Your API Key

```bash
export ANTHROPIC_API_KEY="your-key-here"
# or
export OPENAI_API_KEY="your-key-here"
```

## Step 3: Create a Pipeline

Create `pipelines/hello.pipeline.json`:

```json
{
  "name": "hello-pipeline",
  "description": "My first FlowMason pipeline",
  "version": "1.0.0",
  "stages": [
    {
      "id": "greet",
      "component_type": "generator",
      "config": {
        "prompt": "Say hello to {{input.name}} in a creative way. Keep it under 50 words.",
        "temperature": 0.8
      }
    }
  ]
}
```

## Step 4: Run the Pipeline

```bash
fm run pipelines/hello.pipeline.json --input '{"name": "World"}'
```

Output:
```
FlowMason Pipeline Runner
Pipeline: hello-pipeline
─────────────────────────
[1/1] Running stage: greet (generator)
✓ Stage completed in 1.2s

Result:
{
  "content": "Hello there, magnificent World! May your day sparkle with unexpected joys..."
}
```

## Step 5: Add More Stages

Update `pipelines/hello.pipeline.json` to add processing:

```json
{
  "name": "hello-pipeline",
  "description": "My first FlowMason pipeline",
  "version": "1.0.0",
  "stages": [
    {
      "id": "greet",
      "component_type": "generator",
      "config": {
        "prompt": "Say hello to {{input.name}} in a creative way. Keep it under 50 words.",
        "temperature": 0.8
      }
    },
    {
      "id": "analyze",
      "component_type": "critic",
      "depends_on": ["greet"],
      "config": {
        "content": "{{greet.output.content}}",
        "criteria": ["creativity", "friendliness", "brevity"],
        "scoring_scale": 10
      }
    }
  ]
}
```

Run again:
```bash
fm run pipelines/hello.pipeline.json --input '{"name": "World"}'
```

## Step 6: Debug in VSCode

1. Open the project in VSCode
2. Open `pipelines/hello.pipeline.json`
3. Press `F5` to start debugging
4. Set breakpoints by clicking the gutter or pressing `F9`
5. Step through with `F10`

## Using the Visual Editor

1. Open a `.pipeline.json` file in VSCode
2. Click "Open DAG View" in the editor toolbar
3. Drag and drop to connect stages
4. Configure stages in the sidebar panel

## Common Patterns

### Conditional Branching

```json
{
  "id": "check",
  "component_type": "conditional",
  "depends_on": ["analyze"],
  "config": {
    "condition": "{{analyze.output.overall_score}} >= 7",
    "true_branch": "publish",
    "false_branch": "improve"
  }
}
```

### Error Handling

```json
{
  "id": "safe_fetch",
  "component_type": "trycatch",
  "config": {
    "try_stages": ["fetch_data"],
    "catch_stages": ["fallback"],
    "on_error": "continue"
  }
}
```

### Looping

```json
{
  "id": "process_all",
  "component_type": "foreach",
  "config": {
    "items": "{{input.urls}}",
    "item_variable": "url",
    "stages": ["fetch", "process"],
    "parallel": true,
    "max_concurrency": 5
  }
}
```

## Next Steps

- [Core Concepts](../03-concepts/architecture-overview.md) - Deeper understanding
- [Building Nodes](../04-core-framework/decorators/node.md) - Create custom AI components
- [Building Operators](../04-core-framework/decorators/operator.md) - Create utility components
- [Debugging](../09-debugging-testing/debugging/current-debugging.md) - Debug pipeline execution
- [VSCode Extension](../07-vscode-extension/overview.md) - Full extension guide


---

## 03-concepts/architecture-overview.md

# FlowMason Architecture Overview

## System Components

```
┌─────────────────────────────────────────────────────────────────┐
│                        VSCode Extension                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐ │
│  │   Custom    │  │   Debug     │  │      Test Explorer      │ │
│  │   Editor    │  │   Adapter   │  │      Integration        │ │
│  │  Provider   │  │  (DAP)      │  │       (Future)          │ │
│  └──────┬──────┘  └──────┬──────┘  └───────────┬─────────────┘ │
│         │                │                      │               │
│         └────────────────┼──────────────────────┘               │
│                          │                                      │
│                    ┌─────▼─────┐                                │
│                    │ Extension │                                │
│                    │   Host    │                                │
│                    └─────┬─────┘                                │
└──────────────────────────┼──────────────────────────────────────┘
                           │ HTTP/WebSocket
                    ┌──────▼──────┐
                    │  FlowMason  │
                    │   Studio    │
                    │  Backend    │
                    └──────┬──────┘
                           │
              ┌────────────┼────────────┐
              │            │            │
        ┌─────▼────┐ ┌─────▼────┐ ┌─────▼────┐
        │Component │ │Execution │ │  LLM     │
        │ Registry │ │  Engine  │ │Providers │
        └──────────┘ └──────────┘ └──────────┘
```

## Layer Breakdown

### 1. VSCode Extension Layer

**Location:** `vscode-extension/`

The VSCode extension provides:
- IntelliSense and code completion for `@node`, `@operator`, `@control_flow`
- Diagnostics and linting
- CodeLens (Run/Preview buttons)
- Go to Definition for component references
- Studio lifecycle management (start/stop/restart)
- Component preview webview

**Future:**
- Custom Editor Provider for `.pipeline.json`
- Debug Adapter Protocol integration
- Test Explorer integration

### 2. Studio Layer

**Location:** `studio/flowmason_studio/`

The Studio provides both backend API and frontend UI:

**Backend (FastAPI):**
- REST API for pipelines, components, runs
- WebSocket for real-time execution updates
- ExecutionController for debug commands
- SQLite storage for pipelines and runs

**Frontend (React):**
- Pipeline Builder canvas
- Component palette
- Debug panel with breakpoints
- Stage configuration
- Execution timeline

### 3. Core Framework Layer

**Location:** `core/flowmason_core/`

The core framework provides:
- Decorators: `@node`, `@operator`, `@control_flow`
- Type system: `NodeInput`, `NodeOutput`, `ControlFlowDirective`
- Execution engine: `UniversalExecutor`, `DAGExecutor`
- Registry: Component discovery and loading
- Error handling: `ErrorType`, `FlowMasonError`

### 4. Components Layer

**Location:** `lab/flowmason_lab/`

Built-in components:
- **Control Flow:** Conditional, ForEach, TryCatch, Router, SubPipeline, Return
- **Operators:** HttpRequest, JsonTransform, Filter, SchemaValidate, VariableSet, Logger
- **Nodes:** Generator, Critic, Improver, Selector, Synthesizer

## Data Flow

### Pipeline Execution

```
User Input
    │
    ▼
┌───────────────┐
│ Pipeline      │  Parse pipeline definition
│ Definition    │  Resolve stage dependencies
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ DAGExecutor   │  Topological sort stages
│               │  Execute in dependency order
└───────┬───────┘
        │
        ▼ (for each stage)
┌───────────────┐
│ Universal     │  Resolve input mappings
│ Executor      │  Validate inputs
│               │  Execute component
│               │  Validate outputs
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ Component     │  Node: LLM call
│               │  Operator: Transform
│               │  Control Flow: Directive
└───────┬───────┘
        │
        ▼
┌───────────────┐
│ Results       │  Stage outputs
│               │  Usage metrics
│               │  Trace spans
└───────────────┘
```

### WebSocket Events

```
Client                    Server
   │                         │
   │──── subscribe ─────────►│
   │                         │
   │◄─── SUBSCRIBED ─────────│
   │                         │
   │                         │ (pipeline starts)
   │◄─── RUN_STARTED ────────│
   │                         │
   │◄─── STAGE_STARTED ──────│  (for each stage)
   │◄─── STAGE_COMPLETED ────│
   │                         │
   │◄─── RUN_COMPLETED ──────│
   │                         │
   │──── unsubscribe ───────►│
```

## Key Files

### Core Framework

| File | Purpose |
|------|---------|
| `core/flowmason_core/core/decorators.py` | @node, @operator, @control_flow |
| `core/flowmason_core/core/types.py` | NodeInput, NodeOutput, ControlFlowDirective |
| `core/flowmason_core/execution/universal_executor.py` | Component execution |
| `core/flowmason_core/execution/dag_executor.py` | Pipeline execution |
| `core/flowmason_core/execution/types.py` | ErrorType, FlowMasonError, UsageMetrics |
| `core/flowmason_core/registry/extractor.py` | Metadata extraction |

### Studio

| File | Purpose |
|------|---------|
| `studio/flowmason_studio/api/app.py` | FastAPI application |
| `studio/flowmason_studio/api/routes/` | API endpoints |
| `studio/flowmason_studio/api/websocket.py` | WebSocket handler |
| `studio/flowmason_studio/services/execution_controller.py` | Debug control |
| `studio/frontend/src/pages/PipelineBuilder.tsx` | Pipeline canvas |
| `studio/frontend/src/components/debug/` | Debug UI |

### VSCode Extension

| File | Purpose |
|------|---------|
| `vscode-extension/src/extension.ts` | Extension entry point |
| `vscode-extension/src/commands/` | Command implementations |
| `vscode-extension/src/providers/` | Language providers |
| `vscode-extension/src/services/flowmasonService.ts` | API client |


---

## 03-concepts/control-flow.md

# Control Flow

## What is Control Flow?

**Control Flow** components modify pipeline execution - they enable branching, looping, error handling, and early returns. Unlike nodes and operators that process data, control flow components return **directives** that tell the executor how to proceed.

## Characteristics

| Property | Value |
|----------|-------|
| Decorator | `@control_flow` |
| Requires LLM | No |
| Default timeout | 30 seconds |
| Default color | Pink (#EC4899) |
| Returns | `ControlFlowDirective` |

## Control Flow Types

| Type | Component | Description |
|------|-----------|-------------|
| `conditional` | ConditionalComponent | If/else branching |
| `foreach` | ForEachComponent | Loop over collections |
| `trycatch` | TryCatchComponent | Error handling |
| `router` | RouterComponent | Switch/case routing |
| `subpipeline` | SubPipelineComponent | Call another pipeline |
| `return` | ReturnComponent | Early exit |

## ControlFlowDirective

Control flow components return a `ControlFlowDirective` that modifies execution:

```python
class ControlFlowDirective(BaseModel):
    directive_type: ControlFlowType      # conditional, foreach, etc.
    skip_stages: List[str] = []          # Stages to skip
    execute_stages: List[str] = []       # Stages that were executed
    loop_items: Optional[List[Any]]      # For foreach
    loop_results: Optional[List[Any]]
    current_item: Optional[Any]
    current_index: Optional[int]
    nested_results: Dict[str, Any] = {}  # Sub-execution results
    error: Optional[str]                 # For trycatch
    error_type: Optional[str]
    recovered: bool = False              # Whether error was recovered
    continue_execution: bool = True      # Whether to continue pipeline
    branch_taken: Optional[str]          # For conditional/router
    output_data: Optional[Any]           # Output from control flow
    metadata: Dict[str, Any] = {}
```

## Components

### Conditional (If/Else)

Branch execution based on a boolean condition.

```python
@control_flow(
    name="conditional",
    description="If/else branching",
    category="control-flow",
    control_flow_type="conditional",
    icon="git-branch",
    color="#EC4899"
)
class ConditionalComponent:
    class Input(ControlFlowInput):
        condition: bool = Field(description="Condition to evaluate")
        true_branch: str = Field(description="Stage ID for true path")
        false_branch: Optional[str] = Field(default=None, description="Stage ID for false path")

    class Output(ControlFlowOutput):
        branch_taken: str
        directive: ControlFlowDirective
```

**Usage in pipeline:**
```json
{
  "id": "check-length",
  "component": "conditional",
  "config": {
    "condition": "{{len(input.text) > 1000}}",
    "true_branch": "summarize-long",
    "false_branch": "summarize-short"
  }
}
```

### ForEach (Loop)

Iterate over a collection, executing stages for each item.

```python
@control_flow(
    name="foreach",
    description="Loop over collections",
    category="control-flow",
    control_flow_type="foreach",
    icon="repeat",
    color="#10B981"
)
class ForEachComponent:
    class Input(ControlFlowInput):
        items: List[Any] = Field(description="Items to iterate over")
        loop_stages: List[str] = Field(description="Stages to execute per item")
        parallel: bool = Field(default=False, description="Execute items in parallel")
        max_parallel: int = Field(default=5, description="Max parallel executions")
        break_on_error: bool = Field(default=True, description="Stop on first error")

    class Output(ControlFlowOutput):
        results: List[Any]
        directive: ControlFlowDirective
```

**Usage:**
```json
{
  "id": "process-items",
  "component": "foreach",
  "config": {
    "items": "{{input.documents}}",
    "loop_stages": ["extract", "summarize"],
    "item_variable": "current_doc",
    "index_variable": "doc_index",
    "parallel": true,
    "max_parallel": 3
  }
}
```

**Accessing Loop Variables:**

Inside loop stages, access the current item and index via `{{context.variable_name}}`:

```json
{
  "id": "extract",
  "component_type": "json_transform",
  "depends_on": ["process-items"],
  "config": {
    "data": {
      "item": "{{context.current_doc}}",
      "index": "{{context.doc_index}}"
    },
    "jmespath_expression": "{ content: item.text, position: index }"
  }
}
```

> **Important:** Loop stages must have `depends_on: ["foreach_stage_id"]` to ensure they execute within the foreach context.

### TryCatch (Error Handling)

Handle errors with recovery paths (MuleSoft-inspired).

```python
@control_flow(
    name="trycatch",
    description="Error handling with recovery",
    category="control-flow",
    control_flow_type="trycatch",
    icon="shield",
    color="#EF4444"
)
class TryCatchComponent:
    class Input(ControlFlowInput):
        try_stages: List[str] = Field(description="Stages to try")
        catch_stages: List[str] = Field(default=[], description="Stages on error")
        finally_stages: List[str] = Field(default=[], description="Always execute")
        error_scope: str = Field(default="propagate", description="propagate or continue")
        catch_error_types: List[str] = Field(default=[], description="Specific errors to catch")

    class Output(ControlFlowOutput):
        error: Optional[str]
        error_type: Optional[str]
        recovered: bool
        directive: ControlFlowDirective
```

**Error scopes:**
- `propagate` - Re-raise error after catch (like `on-error-propagate`)
- `continue` - Swallow error, continue pipeline (like `on-error-continue`)

**Usage:**
```json
{
  "id": "safe-api-call",
  "component": "trycatch",
  "config": {
    "try_stages": ["fetch-data"],
    "catch_stages": ["use-fallback"],
    "finally_stages": ["cleanup"],
    "error_scope": "continue"
  }
}
```

**Accessing Results from Try/Catch Stages:**

Downstream stages can access results from nested stages via `{{upstream.nested_stage_id}}`:

```json
{
  "id": "process-result",
  "component_type": "json_transform",
  "depends_on": ["safe-api-call"],
  "config": {
    "data": {
      "api_result": "{{upstream.fetch-data}}",
      "trycatch_info": "{{upstream.safe-api-call}}"
    },
    "jmespath_expression": "{ data: api_result.body, status: trycatch_info.status }"
  }
}
```

> **Note:** Try and catch stages must have `depends_on: ["trycatch_stage_id"]` for proper execution order.

### Router (Switch/Case)

Route to different branches based on a value.

```python
@control_flow(
    name="router",
    description="Switch/case routing",
    category="control-flow",
    control_flow_type="router",
    icon="git-merge",
    color="#F59E0B"
)
class RouterComponent:
    class Input(ControlFlowInput):
        value: Any = Field(description="Value to route on")
        routes: Dict[str, str] = Field(description="Value → stage ID mapping")
        default: Optional[str] = Field(default=None, description="Default stage")

    class Output(ControlFlowOutput):
        route_taken: str
        directive: ControlFlowDirective
```

**Usage:**
```json
{
  "id": "route-by-type",
  "component": "router",
  "config": {
    "value": "{{input.document_type}}",
    "routes": {
      "pdf": "process-pdf",
      "doc": "process-doc",
      "txt": "process-text"
    },
    "default": "process-generic"
  }
}
```

### SubPipeline (Composition)

Call another pipeline as a sub-routine.

```python
@control_flow(
    name="subpipeline",
    description="Call another pipeline",
    category="control-flow",
    control_flow_type="subpipeline",
    icon="workflow",
    color="#6366F1"
)
class SubPipelineComponent:
    class Input(ControlFlowInput):
        pipeline_id: str = Field(description="Pipeline to call")
        pipeline_version: Optional[str] = Field(default=None)
        input_data: Dict[str, Any] = Field(description="Input for sub-pipeline")
        timeout_ms: int = Field(default=60000)

    class Output(ControlFlowOutput):
        pipeline_id: str
        result: Any
        directive: ControlFlowDirective
```

**Usage:**
```json
{
  "id": "run-preprocessing",
  "component": "subpipeline",
  "config": {
    "pipeline_id": "preprocessing-pipeline",
    "input_data": {
      "documents": "{{input.raw_documents}}"
    }
  }
}
```

### Return (Early Exit)

Exit the pipeline early with a return value.

```python
@control_flow(
    name="return",
    description="Early exit from pipeline",
    category="control-flow",
    control_flow_type="return",
    icon="corner-down-left",
    color="#8B5CF6"
)
class ReturnComponent:
    class Input(ControlFlowInput):
        condition: bool = Field(default=True, description="Return if true")
        return_value: Any = Field(description="Value to return")
        message: str = Field(default="", description="Return reason")

    class Output(ControlFlowOutput):
        should_return: bool
        return_value: Any
        directive: ControlFlowDirective
```

**Usage (guard clause):**
```json
{
  "id": "check-input",
  "component": "return",
  "config": {
    "condition": "{{not input.text}}",
    "return_value": {"error": "No input provided"},
    "message": "Empty input"
  }
}
```

## Creating Custom Control Flow

```python
from flowmason_core.core import control_flow, Field
from flowmason_core.core.types import (
    ControlFlowInput,
    ControlFlowOutput,
    ControlFlowDirective,
    ControlFlowType
)

@control_flow(
    name="retry-on-fail",
    description="Retry stages on failure",
    category="control-flow",
    control_flow_type="trycatch"  # Use existing type or define new
)
class RetryOnFailComponent:
    class Input(ControlFlowInput):
        stages: List[str]
        max_retries: int = 3
        delay_ms: int = 1000

    class Output(ControlFlowOutput):
        attempts: int
        success: bool
        directive: ControlFlowDirective

    async def execute(self, input: Input, context) -> Output:
        # Custom retry logic
        directive = ControlFlowDirective(
            directive_type=ControlFlowType.TRYCATCH,
            execute_stages=input.stages,
            metadata={"max_retries": input.max_retries}
        )
        return self.Output(
            attempts=1,
            success=True,
            directive=directive
        )
```

## Best Practices

1. **Keep control flow simple** - Complex logic belongs in operators
2. **Use meaningful stage IDs** - Makes pipelines readable
3. **Handle edge cases** - Empty lists in foreach, missing routes
4. **Consider error handling** - Wrap risky operations in trycatch
5. **Use guard clauses** - Return early for invalid inputs
6. **Avoid deep nesting** - Flatten when possible


---

## 03-concepts/nodes.md

# Nodes

## What is a Node?

A **Node** is an AI-powered component that requires an LLM (Large Language Model) to execute. Nodes perform intelligent tasks like text generation, summarization, analysis, and decision-making.

## Characteristics

| Property | Value |
|----------|-------|
| Decorator | `@node` |
| Requires LLM | Yes |
| Default timeout | 60 seconds |
| Default retries | 3 |
| Deterministic | No (LLM responses vary) |

## Creating a Node

```python
from flowmason_core.core import node, Field
from flowmason_core.core.types import NodeInput, NodeOutput

@node(
    name="summarize-text",
    description="Summarize text using an LLM",
    category="text",
    recommended_providers={"anthropic": ["claude-sonnet-4-20250514"]},
    timeout=60,
    max_retries=3
)
class SummarizeTextNode:
    """Summarizes input text to a specified length."""

    class Input(NodeInput):
        text: str = Field(description="Text to summarize")
        max_length: int = Field(default=100, description="Maximum words in summary")
        style: str = Field(default="concise", description="Summary style")

    class Output(NodeOutput):
        summary: str = Field(description="Generated summary")
        word_count: int = Field(description="Number of words in summary")

    async def execute(self, input: Input, context) -> Output:
        prompt = f"""Summarize the following text in {input.max_length} words or less.
Style: {input.style}

Text:
{input.text}

Summary:"""

        response = await context.llm.generate(
            prompt=prompt,
            max_tokens=input.max_length * 2
        )

        summary = response.text.strip()
        word_count = len(summary.split())

        return self.Output(summary=summary, word_count=word_count)
```

## Decorator Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `name` | str | Required | Unique identifier (kebab-case) |
| `description` | str | Required | Human-readable description |
| `category` | str | `"general"` | Component category |
| `version` | str | `"1.0.0"` | Semantic version |
| `icon` | str | `"cpu"` | Lucide icon name |
| `color` | str | `"#8B5CF6"` | Hex color (purple default) |
| `timeout` | int | `60` | Execution timeout in seconds |
| `max_retries` | int | `3` | Maximum retry attempts |
| `recommended_providers` | dict | `{}` | Provider → models mapping |
| `default_provider` | str | `None` | Default LLM provider |
| `required_capabilities` | list | `[]` | Required LLM capabilities |

## Input/Output Classes

### NodeInput

Base class for node inputs:

```python
class Input(NodeInput):
    # Required field
    text: str

    # Optional with default
    max_length: int = 100

    # With Field metadata
    temperature: float = Field(
        default=0.7,
        ge=0,
        le=2,
        description="LLM temperature"
    )
```

**Validation:**
- `extra="forbid"` - No extra fields allowed
- Validates on assignment
- Strips whitespace from strings

### NodeOutput

Base class for node outputs:

```python
class Output(NodeOutput):
    summary: str
    confidence: float
    metadata: dict = {}
```

**Validation:**
- `extra="allow"` - Extra fields allowed (flexible for LLM responses)

## Context Object

The `context` parameter provides:

```python
async def execute(self, input: Input, context) -> Output:
    # LLM access
    response = await context.llm.generate(prompt="...")
    response = await context.llm.stream(prompt="...")

    # Run metadata
    run_id = context.run_id
    stage_id = context.stage_id

    # Upstream outputs (in pipeline)
    prev_output = context.upstream_outputs.get("previous_stage")
```

## Built-in Nodes

| Node | Description |
|------|-------------|
| `generator` | Create content from prompts |
| `critic` | Evaluate and provide feedback |
| `improver` | Refine content based on criteria |
| `selector` | Choose best option from set |
| `synthesizer` | Combine multiple inputs |

## Best Practices

1. **Clear descriptions** - Help users understand what the node does
2. **Sensible defaults** - Make common cases easy
3. **Input validation** - Use Field constraints
4. **Meaningful outputs** - Include metadata when useful
5. **Handle errors** - LLM calls can fail
6. **Consider tokens** - Estimate token usage for cost

## Example: Generator Node

From `lab/flowmason_lab/nodes/core/generator.py`:

```python
@node(
    name="generator",
    description="Generate content using an LLM provider",
    category="core",
    icon="sparkles",
    color="#8B5CF6",
    recommended_providers={
        "anthropic": ["claude-sonnet-4-20250514"],
        "openai": ["gpt-4o"]
    },
    default_provider="anthropic"
)
class GeneratorNode:
    class Input(NodeInput):
        prompt: str = Field(description="The prompt to send to the LLM")
        system_prompt: Optional[str] = Field(default=None)
        temperature: float = Field(default=0.7, ge=0, le=2)
        max_tokens: int = Field(default=1024, ge=1)

    class Output(NodeOutput):
        content: str = Field(description="Generated content")
        usage: Dict[str, int] = Field(description="Token usage")

    async def execute(self, input: Input, context) -> Output:
        response = await context.llm.generate(
            prompt=input.prompt,
            system_prompt=input.system_prompt,
            temperature=input.temperature,
            max_tokens=input.max_tokens
        )
        return self.Output(
            content=response.text,
            usage=response.usage
        )
```


---

## 03-concepts/operators.md

# Operators

## What is an Operator?

An **Operator** is a deterministic, non-AI component for data transformation and utility tasks. Operators don't require an LLM - they perform predictable operations like HTTP calls, JSON parsing, filtering, and validation.

## Characteristics

| Property | Value |
|----------|-------|
| Decorator | `@operator` |
| Requires LLM | No |
| Default timeout | 30 seconds |
| Deterministic | Yes (same input = same output) |
| Default color | Blue (#3B82F6) |

## Creating an Operator

```python
from flowmason_core.core import operator, Field
from flowmason_core.core.types import OperatorInput, OperatorOutput
from typing import Any, List

@operator(
    name="filter-items",
    description="Filter a list based on a condition",
    category="transform",
    timeout=30
)
class FilterItemsOperator:
    """Filters items from a list based on a field value."""

    class Input(OperatorInput):
        items: List[dict] = Field(description="List of items to filter")
        field: str = Field(description="Field name to check")
        value: Any = Field(description="Value to match")
        operator: str = Field(default="eq", description="Comparison: eq, ne, gt, lt, contains")

    class Output(OperatorOutput):
        filtered: List[dict] = Field(description="Filtered items")
        count: int = Field(description="Number of items after filtering")

    async def execute(self, input: Input, context) -> Output:
        filtered = []
        for item in input.items:
            item_value = item.get(input.field)
            if self._matches(item_value, input.value, input.operator):
                filtered.append(item)

        return self.Output(filtered=filtered, count=len(filtered))

    def _matches(self, item_value, target, op):
        if op == "eq":
            return item_value == target
        elif op == "ne":
            return item_value != target
        elif op == "gt":
            return item_value > target
        elif op == "lt":
            return item_value < target
        elif op == "contains":
            return target in str(item_value)
        return False
```

## Decorator Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `name` | str | Required | Unique identifier (kebab-case) |
| `description` | str | Required | Human-readable description |
| `category` | str | `"general"` | Component category |
| `version` | str | `"1.0.0"` | Semantic version |
| `icon` | str | `"cog"` | Lucide icon name |
| `color` | str | `"#3B82F6"` | Hex color (blue default) |
| `timeout` | int | `30` | Execution timeout in seconds |

**Note:** Operators don't have `recommended_providers`, `max_retries`, or LLM-related parameters.

## Input/Output Classes

### OperatorInput

Base class for operator inputs:

```python
class Input(OperatorInput):
    data: dict
    expression: str = Field(min_length=1)
    timeout: int = Field(default=30, ge=1, le=300)
```

### OperatorOutput

Base class for operator outputs:

```python
class Output(OperatorOutput):
    result: Any
    success: bool
    message: str = ""
```

## Built-in Operators

### Core Operators

| Operator | Description | Use Case |
|----------|-------------|----------|
| `http-request` | Make HTTP calls | API integration |
| `json-transform` | JMESPath queries | Data extraction |
| `filter` | Filter collections | Data filtering |
| `loop` | Iterate over items | Batch processing |
| `schema-validate` | JSON Schema validation | Input validation |
| `variable-set` | Set context variables | State management |
| `logger` | Emit logs | Debugging |

### Control Flow (see [Control Flow](control-flow.md))

| Operator | Description |
|----------|-------------|
| `conditional` | If/else branching |
| `foreach` | Loop iteration |
| `trycatch` | Error handling |
| `router` | Switch/case routing |
| `subpipeline` | Pipeline composition |
| `return` | Early exit |

## Example: HTTP Request Operator

From `lab/flowmason_lab/operators/core/http_request.py`:

```python
@operator(
    name="http-request",
    description="Make HTTP requests to external APIs",
    category="integration",
    icon="globe",
    color="#3B82F6",
    timeout=30
)
class HttpRequestOperator:
    class Input(OperatorInput):
        url: str = Field(description="Request URL")
        method: str = Field(default="GET", description="HTTP method")
        headers: Dict[str, str] = Field(default_factory=dict)
        body: Optional[Dict[str, Any]] = Field(default=None)
        timeout: int = Field(default=30, ge=1, le=300)

    class Output(OperatorOutput):
        status_code: int
        headers: Dict[str, str]
        body: Any
        elapsed_ms: int
        success: bool

    async def execute(self, input: Input, context) -> Output:
        import httpx

        async with httpx.AsyncClient() as client:
            start = time.time()
            response = await client.request(
                method=input.method,
                url=input.url,
                headers=input.headers,
                json=input.body,
                timeout=input.timeout
            )
            elapsed = int((time.time() - start) * 1000)

        return self.Output(
            status_code=response.status_code,
            headers=dict(response.headers),
            body=response.json() if response.headers.get("content-type", "").startswith("application/json") else response.text,
            elapsed_ms=elapsed,
            success=response.is_success
        )
```

## Example: JSON Transform Operator

```python
@operator(
    name="json-transform",
    description="Transform JSON using JMESPath expressions",
    category="transform",
    icon="braces"
)
class JsonTransformOperator:
    class Input(OperatorInput):
        data: Any = Field(description="Input data")
        expression: str = Field(description="JMESPath expression")

    class Output(OperatorOutput):
        result: Any = Field(description="Transformed result")

    async def execute(self, input: Input, context) -> Output:
        import jmespath
        result = jmespath.search(input.expression, input.data)
        return self.Output(result=result)
```

## Operators vs Nodes

| Aspect | Operator | Node |
|--------|----------|------|
| LLM Required | No | Yes |
| Deterministic | Yes | No |
| Default Timeout | 30s | 60s |
| Retries | Not applicable | 3 by default |
| Use Case | Data transformation | AI tasks |
| Default Color | Blue | Purple |

## Best Practices

1. **Keep it simple** - Operators should do one thing well
2. **Handle errors** - Network calls can fail
3. **Validate inputs** - Use Field constraints
4. **Return useful metadata** - Include timing, counts, etc.
5. **Use async** - For I/O operations like HTTP calls
6. **Consider timeouts** - Set appropriate limits


---

## 03-concepts/pipelines.md

# Pipelines

## What is a Pipeline?

A **Pipeline** is a directed acyclic graph (DAG) of stages that process data. Stages are connected by dependencies, and the executor runs them in topological order.

## Pipeline Structure

### Current Format (Studio Database)

Pipelines are currently stored in SQLite with this structure:

```json
{
  "id": "pipeline-uuid",
  "name": "content-processing",
  "description": "Process and summarize content",
  "version": "1.0.0",
  "status": "DRAFT",
  "category": "text",
  "tags": ["content", "summarization"],
  "stages": [...],
  "input_schema": {...},
  "output_schema": {...},
  "sample_input": {...},
  "created_at": "2025-12-11T00:00:00Z",
  "updated_at": "2025-12-11T00:00:00Z"
}
```

### Future Format (`.pipeline.json`)

File-based pipelines for Git versioning:

```json
{
  "name": "content-processing",
  "version": "1.0.0",
  "description": "Process and summarize content",
  "stages": [
    {
      "id": "fetch",
      "component": "http-request",
      "config": {
        "url": "{{input.url}}",
        "method": "GET"
      }
    },
    {
      "id": "summarize",
      "component": "generator",
      "depends_on": ["fetch"],
      "config": {
        "prompt": "Summarize: {{fetch.output.body}}"
      }
    }
  ],
  "input_schema": {
    "type": "object",
    "properties": {
      "url": { "type": "string", "format": "uri" }
    },
    "required": ["url"]
  }
}
```

## Stages

A stage is a single step in the pipeline:

```json
{
  "id": "summarize",
  "component": "generator",
  "depends_on": ["fetch", "clean"],
  "config": {
    "prompt": "{{fetch.output.body}}",
    "max_tokens": 500
  },
  "llm_settings": {
    "provider": "anthropic",
    "model": "claude-sonnet-4-20250514",
    "temperature": 0.7
  }
}
```

### Stage Properties

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `id` | string | Yes | Unique stage identifier |
| `component` | string | Yes | Component name to execute |
| `depends_on` | string[] | No | Stage IDs this depends on |
| `config` | object | Yes | Component input configuration |
| `llm_settings` | object | No | LLM override settings |

## Dependencies

Stages specify dependencies with `depends_on`:

```
       ┌─────────┐
       │  fetch  │
       └────┬────┘
            │
       ┌────▼────┐
       │  clean  │
       └────┬────┘
            │
    ┌───────┴───────┐
    │               │
┌───▼───┐      ┌────▼────┐
│extract│      │summarize│
└───┬───┘      └────┬────┘
    │               │
    └───────┬───────┘
            │
       ┌────▼────┐
       │ combine │
       └─────────┘
```

```json
[
  { "id": "fetch", "component": "http-request" },
  { "id": "clean", "component": "json-transform", "depends_on": ["fetch"] },
  { "id": "extract", "component": "json-transform", "depends_on": ["clean"] },
  { "id": "summarize", "component": "generator", "depends_on": ["clean"] },
  { "id": "combine", "component": "synthesizer", "depends_on": ["extract", "summarize"] }
]
```

## Input Mapping

Reference upstream outputs with template syntax:

### Accessing Upstream Outputs

```json
{
  "config": {
    "text": "{{fetch.output.body}}",
    "count": "{{extract.output.items.length}}"
  }
}
```

### Accessing Pipeline Input

```json
{
  "config": {
    "url": "{{input.url}}",
    "max_length": "{{input.settings.max_length}}"
  }
}
```

### Template Syntax

| Syntax | Description |
|--------|-------------|
| `{{input.field}}` | Pipeline input |
| `{{stage_id.output.field}}` | Stage output |
| `{{stage_id.output.nested.field}}` | Nested field |
| `{{stage_id.output.items[0]}}` | Array index |

## Pipeline Status

| Status | Description |
|--------|-------------|
| `DRAFT` | Being edited, not ready for production |
| `PUBLISHED` | Validated and ready for use |

**Publish Requirements:**
- At least one successful test run
- All stages have valid components
- No circular dependencies

## Execution

### How Execution Works

1. **Parse** - Load pipeline definition
2. **Validate** - Check dependencies, component availability
3. **Topological Sort** - Order stages by dependencies
4. **Execute** - Run each stage in order
5. **Collect Results** - Aggregate outputs and metrics

### Current Execution (Sequential)

The DAGExecutor currently runs stages sequentially:

```
Stage 1 → Stage 2 → Stage 3 → Stage 4
```

Independent stages still run one at a time.

### Future: Parallel Execution

Independent stages could run in parallel:

```
Stage 1 ─┬─► Stage 2a ─┬─► Stage 3
         └─► Stage 2b ─┘
```

## Execution Results

### Run Result

```json
{
  "run_id": "run-uuid",
  "pipeline_id": "pipeline-uuid",
  "status": "COMPLETED",
  "stage_results": {
    "fetch": {
      "status": "success",
      "output": { "body": "..." },
      "duration_ms": 234
    },
    "summarize": {
      "status": "success",
      "output": { "summary": "..." },
      "duration_ms": 1523
    }
  },
  "final_output": { "summary": "..." },
  "usage": {
    "input_tokens": 1500,
    "output_tokens": 200,
    "total_tokens": 1700,
    "cost_usd": 0.0051,
    "duration_ms": 1757
  }
}
```

### Stage Result

```json
{
  "component_id": "summarize",
  "component_type": "generator",
  "status": "success",
  "output": { "summary": "...", "word_count": 50 },
  "usage": {
    "input_tokens": 1500,
    "output_tokens": 200,
    "duration_ms": 1523,
    "provider": "anthropic",
    "model": "claude-sonnet-4-20250514"
  },
  "started_at": "2025-12-11T10:00:00Z",
  "completed_at": "2025-12-11T10:00:01.523Z"
}
```

## Debugging

### Breakpoints

Set breakpoints on stages to pause execution:

```json
{
  "breakpoints": ["summarize", "combine"]
}
```

### Debug Commands

| Command | Description |
|---------|-------------|
| `pause` | Pause execution at current stage |
| `resume` | Continue execution |
| `step` | Execute one stage, then pause |
| `stop` | Stop execution entirely |

### WebSocket Events

Real-time updates during execution:

| Event | Description |
|-------|-------------|
| `RUN_STARTED` | Pipeline execution began |
| `STAGE_STARTED` | Stage execution began |
| `STAGE_COMPLETED` | Stage finished successfully |
| `STAGE_FAILED` | Stage encountered error |
| `BREAKPOINT_HIT` | Paused at breakpoint |
| `RUN_COMPLETED` | Pipeline finished |
| `RUN_FAILED` | Pipeline failed |

## Best Practices

1. **Meaningful stage IDs** - `fetch-user-data` not `stage1`
2. **Single responsibility** - Each stage does one thing
3. **Handle errors** - Use trycatch for risky operations
4. **Validate inputs** - Use guard clauses (return component)
5. **Test incrementally** - Test stages individually first
6. **Version pipelines** - Use semantic versioning
7. **Document** - Clear descriptions for stages


---

## 04-core-framework/decorators/control-flow.md

# @control_flow Decorator

The `@control_flow` decorator creates components that control pipeline execution flow.

## Basic Usage

```python
from flowmason_core import (
    control_flow, BaseControlFlow, ControlFlowInput, ControlFlowOutput,
    ControlFlowDirective, ControlFlowType, Context
)
from pydantic import Field
from typing import Optional

@control_flow(
    name="conditional",
    description="Execute branches based on condition",
    control_flow_type="conditional",
)
class ConditionalComponent(BaseControlFlow):
    class Input(ControlFlowInput):
        condition: bool = Field(description="Condition to evaluate")
        true_branch: str = Field(description="Stage to execute if true")
        false_branch: Optional[str] = Field(default=None, description="Stage if false")

    class Output(ControlFlowOutput):
        branch_taken: str
        directive: ControlFlowDirective

    async def execute(self, input: Input, context: Context) -> Output:
        branch = input.true_branch if input.condition else input.false_branch

        directive = ControlFlowDirective(
            directive_type=ControlFlowType.CONDITIONAL,
            skip_stages=[
                input.false_branch if input.condition else input.true_branch
            ] if (input.true_branch and input.false_branch) else [],
            branch_taken=branch,
        )

        return self.Output(branch_taken=branch, directive=directive)
```

## Decorator Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `name` | `str` | Required | Unique component name |
| `description` | `str` | Required | Human-readable description |
| `control_flow_type` | `str` | Required | Type: conditional, router, foreach, trycatch, subpipeline, return |
| `category` | `str` | `"control-flow"` | Component category |

## Control Flow Types

### conditional

If/else branching based on a condition.

```python
@control_flow(name="conditional", control_flow_type="conditional")
class ConditionalComponent(BaseControlFlow):
    ...
```

**Pipeline Usage:**
```json
{
  "id": "check_status",
  "component_type": "conditional",
  "config": {
    "condition": "{{fetch.output.status_code}} == 200",
    "true_branch": "process_data",
    "false_branch": "handle_error"
  }
}
```

### router

Multi-branch routing (switch/case).

```python
@control_flow(name="router", control_flow_type="router")
class RouterComponent(BaseControlFlow):
    class Input(ControlFlowInput):
        value: str
        routes: dict  # {"case1": "stage1", "case2": "stage2"}
        default: Optional[str] = None

    async def execute(self, input: Input, context: Context) -> Output:
        branch = input.routes.get(input.value, input.default)
        skip = [s for k, s in input.routes.items() if k != input.value]

        directive = ControlFlowDirective(
            directive_type=ControlFlowType.ROUTER,
            skip_stages=skip,
            branch_taken=branch,
        )
        return self.Output(branch_taken=branch, directive=directive)
```

**Pipeline Usage:**
```json
{
  "id": "route_by_type",
  "component_type": "router",
  "config": {
    "value": "{{input.content_type}}",
    "routes": {
      "article": "process_article",
      "video": "process_video",
      "image": "process_image"
    },
    "default": "process_generic"
  }
}
```

### foreach

Loop over collections.

```python
@control_flow(name="foreach", control_flow_type="foreach")
class ForEachComponent(BaseControlFlow):
    class Input(ControlFlowInput):
        items: list
        item_variable: str = "item"
        stages: list[str]  # Stages to execute per item
        parallel: bool = False
        max_concurrency: int = 5

    async def execute(self, input: Input, context: Context) -> Output:
        directive = ControlFlowDirective(
            directive_type=ControlFlowType.FOREACH,
            loop_items=input.items,
            loop_variable=input.item_variable,
            loop_stages=input.stages,
            parallel=input.parallel,
            max_concurrency=input.max_concurrency,
        )
        return self.Output(directive=directive)
```

**Pipeline Usage:**
```json
{
  "id": "process_urls",
  "component_type": "foreach",
  "config": {
    "items": "{{input.urls}}",
    "item_variable": "url",
    "stages": ["fetch_url", "parse_content"],
    "parallel": true,
    "max_concurrency": 10
  }
}
```

### trycatch

Error handling with try/catch semantics.

```python
@control_flow(name="trycatch", control_flow_type="trycatch")
class TryCatchComponent(BaseControlFlow):
    class Input(ControlFlowInput):
        try_stages: list[str]
        catch_stages: list[str]
        finally_stages: Optional[list[str]] = None
        on_error: str = "continue"  # continue or propagate

    async def execute(self, input: Input, context: Context) -> Output:
        directive = ControlFlowDirective(
            directive_type=ControlFlowType.TRYCATCH,
            try_stages=input.try_stages,
            catch_stages=input.catch_stages,
            finally_stages=input.finally_stages or [],
            on_error=input.on_error,
        )
        return self.Output(directive=directive)
```

**Pipeline Usage:**
```json
{
  "id": "safe_operation",
  "component_type": "trycatch",
  "config": {
    "try_stages": ["risky_fetch", "process"],
    "catch_stages": ["log_error", "fallback"],
    "finally_stages": ["cleanup"],
    "on_error": "continue"
  }
}
```

### subpipeline

Execute another pipeline.

```python
@control_flow(name="subpipeline", control_flow_type="subpipeline")
class SubPipelineComponent(BaseControlFlow):
    class Input(ControlFlowInput):
        pipeline: str  # Pipeline name or path
        input: dict    # Input to pass

    async def execute(self, input: Input, context: Context) -> Output:
        directive = ControlFlowDirective(
            directive_type=ControlFlowType.SUBPIPELINE,
            subpipeline_name=input.pipeline,
            subpipeline_input=input.input,
        )
        return self.Output(directive=directive)
```

**Pipeline Usage:**
```json
{
  "id": "run_etl",
  "component_type": "subpipeline",
  "config": {
    "pipeline": "pipelines/etl.pipeline.json",
    "input": {
      "source": "{{input.data_source}}",
      "destination": "{{input.output_path}}"
    }
  }
}
```

### return

Early exit with a value.

```python
@control_flow(name="return", control_flow_type="return")
class ReturnComponent(BaseControlFlow):
    class Input(ControlFlowInput):
        value: Any
        condition: Optional[bool] = True

    async def execute(self, input: Input, context: Context) -> Output:
        if not input.condition:
            directive = ControlFlowDirective(
                directive_type=ControlFlowType.RETURN,
                should_return=False,
            )
        else:
            directive = ControlFlowDirective(
                directive_type=ControlFlowType.RETURN,
                should_return=True,
                return_value=input.value,
            )
        return self.Output(directive=directive)
```

**Pipeline Usage:**
```json
{
  "id": "early_exit",
  "component_type": "return",
  "depends_on": ["validate"],
  "config": {
    "condition": "{{validate.output.valid}} == false",
    "value": {
      "error": "Validation failed",
      "details": "{{validate.output.errors}}"
    }
  }
}
```

## ControlFlowDirective

The directive tells the executor how to modify execution:

```python
@dataclass
class ControlFlowDirective:
    directive_type: ControlFlowType

    # Conditional/Router
    skip_stages: list[str] = field(default_factory=list)
    branch_taken: Optional[str] = None

    # ForEach
    loop_items: list = field(default_factory=list)
    loop_variable: str = "item"
    loop_stages: list[str] = field(default_factory=list)
    parallel: bool = False
    max_concurrency: int = 10

    # TryCatch
    try_stages: list[str] = field(default_factory=list)
    catch_stages: list[str] = field(default_factory=list)
    finally_stages: list[str] = field(default_factory=list)
    on_error: str = "continue"

    # SubPipeline
    subpipeline_name: Optional[str] = None
    subpipeline_input: dict = field(default_factory=dict)

    # Return
    should_return: bool = False
    return_value: Any = None
```

## Built-in Control Flow Components

FlowMason Lab provides these ready-to-use components:

| Component | Type | Description |
|-----------|------|-------------|
| `conditional` | conditional | If/else branching |
| `router` | router | Multi-branch routing |
| `foreach` | foreach | Collection iteration |
| `trycatch` | trycatch | Error handling |
| `subpipeline` | subpipeline | Pipeline composition |
| `return` | return | Early exit |

## Error Handling in Control Flow

### TryCatch Behavior

```
on_error: "continue"
- Catch stages execute on error
- Pipeline continues after catch

on_error: "propagate"
- Catch stages execute on error
- Error re-thrown after catch
```

### Error Context

In catch stages, access error info:

```json
{
  "id": "log_error",
  "component_type": "logger",
  "config": {
    "message": "Error: {{_error.message}}",
    "data": {
      "type": "{{_error.type}}",
      "stage": "{{_error.stage}}"
    }
  }
}
```

## Best Practices

1. **Keep It Simple**: Avoid deeply nested control flow
2. **Use TryCatch**: Wrap risky operations
3. **Parallel When Possible**: Use `parallel: true` for independent iterations
4. **Clear Branch Names**: Use descriptive stage IDs for branches
5. **Limit Concurrency**: Don't overwhelm external services

## See Also

- [Nodes](node.md) - AI components
- [Operators](operator.md) - Utility components
- [Concepts: Control Flow](../../03-concepts/control-flow.md)


---

## 04-core-framework/decorators/node.md

# @node Decorator

The `@node` decorator creates AI-powered components that require LLM providers.

## Basic Usage

```python
from flowmason_core import node, BaseNode, NodeInput, NodeOutput, Context
from pydantic import Field
from typing import Optional, Dict

@node(
    name="summarizer",
    description="Summarize text content",
    category="text",
)
class SummarizerNode(BaseNode):
    class Input(NodeInput):
        text: str = Field(description="Text to summarize")
        max_length: int = Field(default=200, description="Maximum summary length")
        style: str = Field(default="concise", description="Summary style")

    class Output(NodeOutput):
        summary: str
        word_count: int

    async def execute(self, input: Input, context: Context) -> Output:
        response = await context.llm.generate(
            prompt=f"Summarize the following text in {input.max_length} words or less. Style: {input.style}\n\n{input.text}",
            system="You are a professional summarizer.",
            temperature=0.3,
        )
        summary = response.text
        return self.Output(
            summary=summary,
            word_count=len(summary.split())
        )
```

## Decorator Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `name` | `str` | Required | Unique component name |
| `description` | `str` | Required | Human-readable description |
| `category` | `str` | `"general"` | Component category for organization |
| `tags` | `list[str]` | `[]` | Searchable tags |
| `timeout` | `int` | `60` | Execution timeout in seconds |
| `max_retries` | `int` | `3` | Maximum retry attempts |
| `retry_delay` | `float` | `1.0` | Initial delay between retries |
| `retry_backoff` | `float` | `2.0` | Backoff multiplier for retries |
| `retryable_errors` | `list[ErrorType]` | `[TIMEOUT, PROVIDER]` | Errors that trigger retry |
| `recommended_providers` | `dict` | `{}` | Recommended LLM providers and models |

## Full Example with All Options

```python
from flowmason_core import (
    node, BaseNode, NodeInput, NodeOutput, Context, ErrorType
)
from pydantic import Field
from typing import Optional, Dict, List

@node(
    name="content-generator",
    description="Generate content based on prompts with quality controls",
    category="generation",
    tags=["content", "llm", "creative"],
    timeout=120,  # 2 minutes
    max_retries=3,
    retry_delay=2.0,
    retry_backoff=2.0,
    retryable_errors=[ErrorType.TIMEOUT, ErrorType.PROVIDER],
    recommended_providers={
        "anthropic": ["claude-sonnet-4-20250514", "claude-3-haiku-20240307"],
        "openai": ["gpt-4o", "gpt-4o-mini"],
    }
)
class ContentGeneratorNode(BaseNode):
    """
    Generates content with configurable creativity and length.

    Supports multiple content types and quality validation.
    """

    class Input(NodeInput):
        prompt: str = Field(
            description="The content generation prompt"
        )
        content_type: str = Field(
            default="article",
            description="Type of content to generate"
        )
        tone: str = Field(
            default="professional",
            description="Writing tone"
        )
        max_tokens: int = Field(
            default=1024,
            ge=1,
            le=4096,
            description="Maximum output tokens"
        )
        temperature: float = Field(
            default=0.7,
            ge=0.0,
            le=2.0,
            description="Creativity level (0=deterministic, 2=creative)"
        )
        system_prompt: Optional[str] = Field(
            default=None,
            description="Custom system prompt override"
        )

    class Output(NodeOutput):
        content: str
        token_count: int
        model_used: str
        metadata: Dict[str, any]

    async def execute(self, input: Input, context: Context) -> Output:
        # Build system prompt
        system = input.system_prompt or f"""You are a {input.tone} content writer.
Generate {input.content_type} content based on the user's prompt.
Be engaging and well-structured."""

        # Generate content
        response = await context.llm.generate(
            prompt=input.prompt,
            system=system,
            temperature=input.temperature,
            max_tokens=input.max_tokens,
        )

        return self.Output(
            content=response.text,
            token_count=response.usage.get("output_tokens", 0),
            model_used=response.model,
            metadata={
                "content_type": input.content_type,
                "tone": input.tone,
                "finish_reason": response.finish_reason,
            }
        )
```

## The Context Object

The `context` parameter provides access to runtime services:

```python
async def execute(self, input: Input, context: Context) -> Output:
    # LLM access
    response = await context.llm.generate(prompt="...", system="...")

    # Streaming (if supported)
    async for chunk in context.llm.stream_async(prompt="..."):
        # Process streaming tokens
        pass

    # Run ID for tracking
    run_id = context.run_id

    # Stage ID
    stage_id = context.stage_id

    # Access variables from previous stages
    previous_output = context.variables.get("previous_stage.output")

    # Custom logging
    context.log("Processing started", level="info")
```

## LLM Provider Interface

The `context.llm` provides these methods:

### generate()

```python
response = await context.llm.generate(
    prompt="User message",
    system="System instructions",
    model="claude-sonnet-4-20250514",  # Optional, uses default
    temperature=0.7,
    max_tokens=1024,
    stop_sequences=["END"],  # Optional
)

# Response object
response.text        # Generated text
response.model       # Model used
response.usage       # {"input_tokens": N, "output_tokens": N}
response.finish_reason  # "end_turn", "max_tokens", etc.
```

### stream_async()

```python
full_response = ""
async for chunk in context.llm.stream_async(
    prompt="User message",
    system="System instructions",
    temperature=0.7,
):
    full_response += chunk
    # Process each token as it arrives
```

## Input/Output Types

### Built-in Field Types

```python
from pydantic import Field
from typing import Optional, List, Dict, Any, Union

class Input(NodeInput):
    # Required string
    text: str

    # Optional with default
    language: str = "en"

    # With description and validation
    count: int = Field(
        default=10,
        ge=1,
        le=100,
        description="Number of items"
    )

    # Optional field
    metadata: Optional[Dict[str, Any]] = None

    # List of items
    tags: List[str] = Field(default_factory=list)

    # Union types
    source: Union[str, List[str]] = Field(description="Single URL or list of URLs")
```

### Output Types

```python
class Output(NodeOutput):
    # Simple types
    result: str
    count: int
    score: float
    success: bool

    # Complex types
    items: List[Dict[str, Any]]
    metadata: Dict[str, Any]

    # Optional
    error: Optional[str] = None
```

## Error Handling

```python
from flowmason_core import FlowMasonError, ErrorType

async def execute(self, input: Input, context: Context) -> Output:
    try:
        response = await context.llm.generate(prompt=input.prompt)
        return self.Output(content=response.text)
    except Exception as e:
        # Raise typed error for flow control
        raise FlowMasonError(
            error_type=ErrorType.COMPONENT,
            message=f"Generation failed: {str(e)}",
            recoverable=True,
            details={"prompt_length": len(input.prompt)}
        )
```

### Error Types

| Type | When to Use |
|------|------------|
| `VALIDATION` | Input validation failures |
| `COMPONENT` | Component-specific errors |
| `PROVIDER` | LLM provider errors (retryable) |
| `TIMEOUT` | Execution timeout (retryable) |
| `CONFIGURATION` | Configuration errors |
| `CONNECTIVITY` | Network errors |

## Using in Pipelines

```json
{
  "id": "generate_content",
  "component_type": "content-generator",
  "config": {
    "prompt": "Write about {{input.topic}}",
    "content_type": "blog_post",
    "tone": "casual",
    "temperature": 0.8,
    "max_tokens": 2000
  }
}
```

## Best Practices

1. **Clear Descriptions**: Document inputs/outputs thoroughly for IDE support
2. **Sensible Defaults**: Provide defaults that work for common cases
3. **Validation**: Use Pydantic constraints (`ge`, `le`, `regex`, etc.)
4. **Error Handling**: Catch and wrap errors with appropriate types
5. **Timeouts**: Set realistic timeouts for LLM operations
6. **Temperature**: Match temperature to task (low for facts, high for creativity)

## See Also

- [Operators](operator.md) - Non-AI components
- [Control Flow](control-flow.md) - Flow control components
- [Concepts: Nodes](../../03-concepts/nodes.md) - Node concepts


---

## 04-core-framework/decorators/operator.md

# @operator Decorator

The `@operator` decorator creates deterministic, non-AI components for data transformation and utility operations.

## Basic Usage

```python
from flowmason_core import operator, BaseOperator, OperatorInput, OperatorOutput, Context
from pydantic import Field
from typing import Any, Dict

@operator(
    name="json-transform",
    description="Transform JSON data using JMESPath expressions",
    category="transform",
)
class JsonTransformOperator(BaseOperator):
    class Input(OperatorInput):
        data: Any = Field(description="Input data to transform")
        expression: str = Field(description="JMESPath expression")

    class Output(OperatorOutput):
        result: Any

    async def execute(self, input: Input, context: Context) -> Output:
        import jmespath
        result = jmespath.search(input.expression, input.data)
        return self.Output(result=result)
```

## Decorator Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `name` | `str` | Required | Unique component name |
| `description` | `str` | Required | Human-readable description |
| `category` | `str` | `"general"` | Component category |
| `tags` | `list[str]` | `[]` | Searchable tags |
| `timeout` | `int` | `30` | Execution timeout (seconds) |
| `max_retries` | `int` | `0` | Retries (usually 0 for deterministic ops) |

## Key Differences from @node

| Aspect | @node | @operator |
|--------|-------|-----------|
| **Purpose** | AI/LLM operations | Deterministic transformations |
| **Default Timeout** | 60s | 30s |
| **Default Retries** | 3 | 0 |
| **LLM Access** | Yes | Not recommended |
| **Idempotent** | May vary | Should be |

## Full Example

```python
from flowmason_core import operator, BaseOperator, OperatorInput, OperatorOutput, Context
from pydantic import Field
from typing import Any, Dict, List, Optional
import httpx

@operator(
    name="http-request",
    description="Make HTTP requests to external APIs",
    category="http",
    tags=["http", "api", "fetch"],
    timeout=60,  # Allow longer for network ops
)
class HttpRequestOperator(BaseOperator):
    """
    Make HTTP requests with configurable method, headers, and body.

    Supports GET, POST, PUT, DELETE methods with JSON payloads.
    """

    class Input(OperatorInput):
        url: str = Field(description="Request URL")
        method: str = Field(
            default="GET",
            pattern="^(GET|POST|PUT|DELETE|PATCH)$",
            description="HTTP method"
        )
        headers: Dict[str, str] = Field(
            default_factory=dict,
            description="Request headers"
        )
        body: Optional[Any] = Field(
            default=None,
            description="Request body (JSON)"
        )
        timeout: int = Field(
            default=30,
            ge=1,
            le=300,
            description="Request timeout in seconds"
        )

    class Output(OperatorOutput):
        status_code: int
        body: Any
        headers: Dict[str, str]
        elapsed_ms: float

    async def execute(self, input: Input, context: Context) -> Output:
        async with httpx.AsyncClient() as client:
            response = await client.request(
                method=input.method,
                url=input.url,
                headers=input.headers,
                json=input.body if input.body else None,
                timeout=input.timeout,
            )

            # Parse response body
            try:
                body = response.json()
            except:
                body = response.text

            return self.Output(
                status_code=response.status_code,
                body=body,
                headers=dict(response.headers),
                elapsed_ms=response.elapsed.total_seconds() * 1000,
            )
```

## Common Operator Patterns

### Data Filtering

```python
@operator(
    name="filter",
    description="Filter items based on condition",
    category="transform",
)
class FilterOperator(BaseOperator):
    class Input(OperatorInput):
        items: List[Any]
        condition: str = Field(description="Python expression using 'item'")

    class Output(OperatorOutput):
        result: List[Any]
        filtered_count: int

    async def execute(self, input: Input, context: Context) -> Output:
        result = []
        for item in input.items:
            # Safe eval with limited scope
            if eval(input.condition, {"item": item, "len": len, "str": str}):
                result.append(item)

        return self.Output(
            result=result,
            filtered_count=len(input.items) - len(result)
        )
```

### JSON Schema Validation

```python
@operator(
    name="schema-validate",
    description="Validate data against JSON Schema",
    category="validation",
)
class SchemaValidateOperator(BaseOperator):
    class Input(OperatorInput):
        data: Any
        schema: Dict[str, Any]

    class Output(OperatorOutput):
        valid: bool
        errors: List[str]

    async def execute(self, input: Input, context: Context) -> Output:
        from jsonschema import validate, ValidationError, Draft7Validator

        validator = Draft7Validator(input.schema)
        errors = []

        for error in validator.iter_errors(input.data):
            errors.append(f"{error.json_path}: {error.message}")

        return self.Output(
            valid=len(errors) == 0,
            errors=errors
        )
```

### Variable Setting

```python
@operator(
    name="variable-set",
    description="Set context variables for use in later stages",
    category="utility",
)
class VariableSetOperator(BaseOperator):
    class Input(OperatorInput):
        variables: Dict[str, Any] = Field(
            description="Variables to set in context"
        )

    class Output(OperatorOutput):
        set_variables: List[str]

    async def execute(self, input: Input, context: Context) -> Output:
        for key, value in input.variables.items():
            context.variables[key] = value

        return self.Output(set_variables=list(input.variables.keys()))
```

### Logging

```python
@operator(
    name="logger",
    description="Log messages for debugging and observability",
    category="utility",
)
class LoggerOperator(BaseOperator):
    class Input(OperatorInput):
        message: str
        level: str = Field(
            default="info",
            pattern="^(debug|info|warning|error)$"
        )
        data: Optional[Any] = None

    class Output(OperatorOutput):
        logged: bool

    async def execute(self, input: Input, context: Context) -> Output:
        context.log(input.message, level=input.level, data=input.data)
        return self.Output(logged=True)
```

## Using in Pipelines

```json
{
  "stages": [
    {
      "id": "fetch",
      "component_type": "http-request",
      "config": {
        "url": "https://api.example.com/data",
        "method": "GET",
        "headers": {
          "Authorization": "Bearer {{input.api_key}}"
        }
      }
    },
    {
      "id": "transform",
      "component_type": "json-transform",
      "depends_on": ["fetch"],
      "config": {
        "data": "{{fetch.output.body}}",
        "expression": "items[?active==`true`].{name: name, id: id}"
      }
    },
    {
      "id": "validate",
      "component_type": "schema-validate",
      "depends_on": ["transform"],
      "config": {
        "data": "{{transform.output.result}}",
        "schema": {
          "type": "array",
          "items": {
            "type": "object",
            "required": ["name", "id"]
          }
        }
      }
    }
  ]
}
```

## Error Handling

```python
from flowmason_core import FlowMasonError, ErrorType

async def execute(self, input: Input, context: Context) -> Output:
    if not input.url.startswith(("http://", "https://")):
        raise FlowMasonError(
            error_type=ErrorType.VALIDATION,
            message="Invalid URL scheme",
            recoverable=False,
        )

    try:
        # ... operation
        pass
    except httpx.TimeoutException:
        raise FlowMasonError(
            error_type=ErrorType.CONNECTIVITY,
            message="Request timed out",
            recoverable=True,  # Can be retried
        )
```

## Best Practices

1. **Idempotency**: Operators should produce the same output for the same input
2. **No Side Effects**: Avoid modifying external state when possible
3. **Fast Execution**: Keep operators lightweight (use @node for heavy operations)
4. **Clear Errors**: Provide descriptive error messages
5. **Type Safety**: Use Pydantic validation for inputs

## See Also

- [Nodes](node.md) - AI-powered components
- [Control Flow](control-flow.md) - Flow control components
- [Concepts: Operators](../../03-concepts/operators.md) - Operator concepts


---

## 05-security/secrets-management.md

# Secrets Management

FlowMason provides encrypted storage for sensitive values like API keys, tokens, and credentials.

## Overview

The secrets management system:
- Uses Fernet symmetric encryption (AES-128)
- Derives per-organization encryption keys
- Supports key rotation
- Logs all secret access for auditing

## Installation

Install with secrets support:

```bash
pip install flowmason[secrets]
```

Or install cryptography separately:

```bash
pip install cryptography
```

## Configuration

### Environment Variable

Set the master encryption key:

```bash
export FLOWMASON_SECRETS_KEY="your-32-char-secret-key-here"
```

**Important:** This key is used to derive organization-specific encryption keys. Keep it secure!

If not set, a default key is derived from the organization ID (not recommended for production).

### Storage Location

Secrets are stored in:
- `~/.flowmason/secrets/<org-hash>/`

Each secret has two files:
- `<secret-hash>.secret` - Encrypted value
- `<secret-hash>.meta` - Unencrypted metadata (name, description, category)

## API Endpoints

### List Secrets

```http
GET /api/v1/secrets
Authorization: Bearer <api-key>
```

Returns metadata for all secrets (no values).

### Create/Update Secret

```http
POST /api/v1/secrets
Authorization: Bearer <api-key>
Content-Type: application/json

{
  "name": "OPENAI_API_KEY",
  "value": "sk-...",
  "description": "OpenAI API key for production",
  "category": "api_key",
  "expires_at": "2025-12-31T23:59:59Z"
}
```

Categories: `api_key`, `token`, `credential`, `other`

### Get Secret Value

```http
GET /api/v1/secrets/{name}
Authorization: Bearer <api-key>
```

Requires full API key scope. Access is audit logged.

### Delete Secret

```http
DELETE /api/v1/secrets/{name}
Authorization: Bearer <api-key>
```

### Get Metadata Only

```http
GET /api/v1/secrets/{name}/metadata
Authorization: Bearer <api-key>
```

Returns metadata without the value.

## Python API

```python
from flowmason_studio.services.secrets import SecretsService

# Initialize for an organization
secrets = SecretsService(org_id="my-org")

# Store a secret
secrets.set(
    name="OPENAI_API_KEY",
    value="sk-...",
    description="OpenAI API key",
    category="api_key"
)

# Retrieve a secret
value = secrets.get("OPENAI_API_KEY")

# List all secrets (metadata only)
for secret in secrets.list():
    print(f"{secret.name}: {secret.category}")

# Check if secret exists
if secrets.exists("OPENAI_API_KEY"):
    ...

# Delete a secret
secrets.delete("OPENAI_API_KEY")
```

## Key Rotation

Rotate the master encryption key:

```python
secrets.rotate_key("new-master-key")
```

This re-encrypts all secrets with the new key.

## Security Best Practices

1. **Set FLOWMASON_SECRETS_KEY** in production
2. **Rotate keys periodically** (recommended: every 90 days)
3. **Use expiration dates** for temporary credentials
4. **Monitor audit logs** for suspicious access
5. **Limit scope** - only use full-scope API keys when needed

## Audit Logging

All secret operations are logged:
- `secret.create` - Secret created or updated
- `secret.read` - Secret value accessed
- `secret.delete` - Secret deleted

View audit logs:

```http
GET /api/v1/auth/audit-log?resource_type=secret
```

## Integration with Pipelines

Secrets can be referenced in pipelines using the `secrets` context:

```json
{
  "stages": [
    {
      "id": "call-api",
      "component_type": "http_request",
      "config": {
        "headers": {
          "Authorization": "Bearer {{secrets.OPENAI_API_KEY}}"
        }
      }
    }
  ]
}
```

The executor resolves `{{secrets.NAME}}` at runtime from the organization's encrypted storage.

## Error Handling

| Error | Meaning |
|-------|---------|
| 404 | Secret not found |
| 410 | Secret expired |
| 500 | Decryption failed (key mismatch) |


---

## 06-studio/api/input-output.md

# Input/Output Architecture

FlowMason supports flexible input and output routing for pipelines, enabling:
- Named pipeline invocation (call by name, not ID)
- Declarative output routing (designer defaults + caller overrides)
- Multiple destination types (webhook, email, database, message queue)
- Per-org security via allowlists

## Named Pipeline Invocation

Pipelines can be invoked by name with optional version pinning:

```bash
POST /api/v1/run
{
  "pipeline": "customer-support-triage",       # Latest version
  "input": { "ticket_id": "T-123", "message": "..." }
}

# Or with version pinning:
POST /api/v1/run
{
  "pipeline": "customer-support-triage@1.0.0", # Specific version
  "input": { "ticket_id": "T-123", "message": "..." }
}
```

### RunPipelineRequest

| Field | Type | Description |
|-------|------|-------------|
| `pipeline` | string | Pipeline name with optional version: `"my-pipeline"` or `"my-pipeline@1.0.0"` |
| `input` | object | Pipeline input data |
| `output_config` | PipelineOutputConfig | Optional caller-specified output configuration |
| `async_mode` | boolean | If true (default), returns immediately with run_id |
| `callback_url` | string | Shorthand for adding a webhook destination |

### RunPipelineResponse

| Field | Type | Description |
|-------|------|-------------|
| `run_id` | string | Unique run identifier |
| `pipeline_id` | string | Resolved pipeline ID |
| `pipeline_name` | string | Pipeline name |
| `pipeline_version` | string | Pipeline version |
| `status` | RunStatus | Current run status |
| `result` | any | Pipeline result (only if async_mode=false) |
| `delivery_report` | OutputDeliveryReport | Delivery results (only if async_mode=false) |

## Output Destinations

### Destination Types

FlowMason supports four output destination types:

#### Webhook

Send results via HTTP POST/PUT:

```json
{
  "id": "crm-webhook",
  "type": "webhook",
  "name": "Update CRM",
  "config": {
    "url": "https://api.salesforce.com/webhook",
    "method": "POST",
    "headers": { "Authorization": "Bearer {{env.SF_TOKEN}}" },
    "timeout_ms": 30000,
    "retry_count": 3
  },
  "on_success": true,
  "on_error": false
}
```

#### Email

Send notifications via email:

```json
{
  "id": "ops-email",
  "type": "email",
  "name": "Alert Ops Team",
  "config": {
    "to": ["ops@company.com"],
    "cc": ["manager@company.com"],
    "subject_template": "Pipeline {{pipeline_name}} completed",
    "body_template": "Result: {{result | tojson}}",
    "is_html": false
  },
  "on_success": false,
  "on_error": true
}
```

#### Database

Store results in a database:

```json
{
  "id": "results-db",
  "type": "database",
  "name": "Store in Analytics DB",
  "config": {
    "connection_id": "conn_abc123",
    "table": "pipeline_results",
    "operation": "insert",
    "column_mapping": {
      "run_id": "run_id",
      "output": "result_json",
      "completed_at": "timestamp"
    }
  },
  "on_success": true
}
```

#### Message Queue

Publish to a message queue:

```json
{
  "id": "kafka-events",
  "type": "message_queue",
  "name": "Publish to Kafka",
  "config": {
    "connection_id": "conn_kafka_prod",
    "queue_name": "pipeline-events",
    "message_template": "{{ result | tojson }}"
  },
  "on_success": true
}
```

### OutputDestination Schema

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique destination identifier |
| `type` | enum | `webhook`, `email`, `database`, `message_queue` |
| `name` | string | Human-readable name |
| `enabled` | boolean | Whether destination is active (default: true) |
| `config` | object | Type-specific configuration |
| `on_success` | boolean | Deliver on successful completion (default: true) |
| `on_error` | boolean | Deliver on pipeline error (default: false) |
| `error_types` | string[] | Filter error delivery to specific types |
| `payload_template` | string | Jinja2 template to transform output |

## Pipeline Output Configuration

Pipelines can define default output destinations that run automatically:

```json
{
  "name": "customer-support-triage",
  "version": "1.0.0",
  "output_config": {
    "destinations": [
      {
        "id": "webhook-crm",
        "type": "webhook",
        "name": "Update CRM",
        "on_success": true,
        "config": { "url": "https://api.salesforce.com/webhook" }
      },
      {
        "id": "email-ops",
        "type": "email",
        "name": "Alert Ops Team",
        "on_error": true,
        "error_types": ["TIMEOUT", "CONNECTIVITY"],
        "config": { "to": ["ops@company.com"] }
      }
    ],
    "allow_caller_destinations": true,
    "allow_caller_override": false
  },
  "stages": [...]
}
```

### Config Merging

| Pipeline Config | Caller Behavior |
|-----------------|-----------------|
| `allow_caller_destinations: true` | Caller destinations are added to designer defaults |
| `allow_caller_destinations: false` | Caller destinations are ignored |
| `allow_caller_override: true` | Caller can replace all designer defaults |
| `allow_caller_override: false` | Designer defaults always run |

## Security: Allowlist System

All output destinations must be pre-approved in the organization's allowlist.

### Allowlist Entry Types

| Type | Pattern Example | Description |
|------|-----------------|-------------|
| `webhook_domain` | `*.salesforce.com` | Allow any subdomain |
| `webhook_url` | `https://api.example.com/webhook` | Exact URL match |
| `email_domain` | `@company.com` | Allow emails to domain |
| `database_connection` | `conn_abc123` | Reference stored connection |
| `message_queue_connection` | `conn_kafka_prod` | Reference stored connection |

### Allowlist API

```bash
# Create allowlist entry
POST /api/v1/allowlist
{
  "entry_type": "webhook_domain",
  "pattern": "*.salesforce.com",
  "description": "Salesforce webhooks"
}

# List entries
GET /api/v1/allowlist

# Validate a destination
POST /api/v1/allowlist/validate
{
  "destination_type": "webhook",
  "config": { "url": "https://api.salesforce.com/webhook" }
}
# Response: { "is_allowed": true, "matched_entry": "allow_xxx" }

# Delete entry
DELETE /api/v1/allowlist/{id}
```

## Stored Connections

Database and message queue destinations use stored connections for secure credential management.

### Connection Types

- `postgresql`, `mysql`, `mongodb` - Database connections
- `kafka`, `rabbitmq`, `sqs`, `redis` - Message queue connections

### Connections API

```bash
# Create stored connection
POST /api/v1/connections
{
  "name": "Production PostgreSQL",
  "connection_type": "postgresql",
  "host": "db.example.com",
  "port": 5432,
  "database": "analytics",
  "username": "pipeline_user",
  "password": "secret123",
  "ssl_enabled": true
}

# List connections (credentials hidden)
GET /api/v1/connections

# Test connection
POST /api/v1/connections/{id}/test

# Delete connection
DELETE /api/v1/connections/{id}
```

## Delivery Logging

All output deliveries are logged for observability:

```bash
# Get delivery log for a run
GET /api/v1/deliveries/{run_id}

# Response:
{
  "run_id": "run_abc123",
  "deliveries": [
    {
      "destination_id": "webhook-crm",
      "destination_type": "webhook",
      "status": "success",
      "response_code": 200,
      "started_at": "2024-01-15T10:30:00Z",
      "completed_at": "2024-01-15T10:30:01Z",
      "retry_count": 0
    },
    {
      "destination_id": "email-ops",
      "destination_type": "email",
      "status": "skipped",
      "error": "on_error=true but pipeline succeeded"
    }
  ]
}
```

## OutputRouterOperator

For routing within pipelines, use the `OutputRouterOperator`:

```python
from flowmason_lab.operators import OutputRouterOperator

# In a pipeline stage:
{
  "id": "send-results",
  "component_type": "output_router",
  "config": {
    "data": "{{previous_stage.output}}",
    "destinations": [
      {
        "id": "webhook-1",
        "type": "webhook",
        "name": "CRM Webhook",
        "config": { "url": "https://api.example.com/webhook" }
      }
    ],
    "parallel": true,
    "fail_on_error": false
  }
}
```

## ErrorRouterOperator

For error notifications in TryCatch handlers:

```python
from flowmason_lab.operators import ErrorRouterOperator

# In a TryCatch error handler:
{
  "id": "notify-error",
  "component_type": "error_router",
  "config": {
    "error_type": "{{error.type}}",
    "error_message": "{{error.message}}",
    "stage_id": "{{error.stage_id}}",
    "severity": "critical",
    "destinations": [
      {
        "id": "pagerduty",
        "type": "webhook",
        "name": "PagerDuty Alert",
        "config": { "url": "https://events.pagerduty.com/v2/enqueue" }
      }
    ]
  }
}
```

## Complete Example

```bash
# 1. Set up allowlist (admin)
POST /api/v1/allowlist
{ "entry_type": "webhook_domain", "pattern": "*.myapp.com" }

# 2. Create pipeline with output config (designer)
POST /api/v1/pipelines
{
  "name": "order-processor",
  "output_config": {
    "destinations": [
      { "id": "default-webhook", "type": "webhook", "config": {"url": "https://api.myapp.com/orders"} }
    ],
    "allow_caller_destinations": true
  },
  "stages": [...]
}

# 3. Run pipeline with caller webhook (caller)
POST /api/v1/run
{
  "pipeline": "order-processor",
  "input": { "order_id": "ORD-123" },
  "output_config": {
    "destinations": [
      { "id": "my-callback", "type": "webhook", "config": {"url": "https://callback.myapp.com/done"} }
    ]
  }
}
# Both default-webhook AND my-callback will receive the result
```


---

## 06-studio/docker.md

# Docker Deployment

FlowMason Studio provides Docker configurations for local development, staging, and production environments.

## Deployment Options

| Environment | Config File | Use Case |
|-------------|-------------|----------|
| **Local** | `docker-compose.yml` | Development, testing |
| **Development** | `docker-compose.dev.yml` | Hot reload, debugging |
| **Staging** | `docker-compose.staging.yml` | Pre-production testing |
| **Production** | `docker-compose.prod.yml` | Production deployment |

---

## Local Development

### Quick Start

```bash
# Start Studio (builds image if needed)
docker-compose up

# Studio is now available at http://localhost:8999
```

## Configuration Options

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `FLOWMASON_PORT` | `8999` | Port to expose Studio on |
| `PIPELINES_DIR` | `./pipelines` | Local directory to mount for pipelines |
| `OPENAI_API_KEY` | - | OpenAI API key for LLM providers |
| `ANTHROPIC_API_KEY` | - | Anthropic API key for Claude |

### Custom Port

```bash
FLOWMASON_PORT=3000 docker-compose up
```

### Custom Pipeline Directory

```bash
PIPELINES_DIR=/path/to/my/pipelines docker-compose up
```

### With API Keys

```bash
OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... docker-compose up
```

## Development Mode

For active development with hot reload:

```bash
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
```

This enables:
- **Hot reload**: Python code changes are automatically reloaded
- **Source mounting**: Local source code is mounted into the container
- **Debug logging**: More verbose logging output

## Docker Commands Reference

```bash
# Start in background
docker-compose up -d

# View logs
docker-compose logs -f

# Stop
docker-compose down

# Rebuild image (after code changes)
docker-compose build

# Remove all data (fresh start)
docker-compose down -v
```

## Architecture

The Docker setup uses a multi-stage build:

1. **Frontend Build Stage**: Builds the React frontend with Node.js
2. **Runtime Stage**: Python 3.11 slim image with:
   - FlowMason core, studio, and lab packages
   - Built frontend static files
   - Uvicorn ASGI server

## Data Persistence

Data is persisted in a Docker volume:

- **`flowmason-data`**: Contains SQLite database, run history, and settings

To completely reset:

```bash
docker-compose down -v
```

## Health Check

The container includes a health check that verifies Studio is responding:

```bash
# Check container health
docker-compose ps
```

The `/health` endpoint returns:
```json
{
  "status": "healthy",
  "version": "1.0.0"
}
```

## Troubleshooting

### Port Already in Use

```bash
# Use a different port
FLOWMASON_PORT=9000 docker-compose up
```

### Build Failures

```bash
# Rebuild without cache
docker-compose build --no-cache
```

### Permission Issues

If you encounter permission issues with mounted volumes:

```bash
# Run with current user (Linux)
docker-compose run --user $(id -u):$(id -g) studio
```

---

## Staging Deployment

The staging environment includes PostgreSQL, Redis, and Traefik with auto-SSL.

### Prerequisites

1. A server with Docker and Docker Compose installed
2. A domain name pointing to your server
3. Ports 80 and 443 available

### Setup

```bash
# Copy environment template
cp .env.example .env

# Edit with your values
nano .env
```

Required environment variables:
```bash
DOMAIN=flowmason.example.com
ACME_EMAIL=admin@example.com
POSTGRES_PASSWORD=your-strong-password
REDIS_PASSWORD=your-strong-password
```

### Deploy

```bash
# Start all services
docker-compose -f docker-compose.staging.yml up -d

# View logs
docker-compose -f docker-compose.staging.yml logs -f

# Check status
docker-compose -f docker-compose.staging.yml ps
```

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                        Internet                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  Traefik (Reverse Proxy)                                     │
│  - Auto-SSL via Let's Encrypt                               │
│  - HTTP → HTTPS redirect                                     │
│  - Ports: 80, 443                                           │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  FlowMason Studio                                            │
│  - Single instance                                           │
│  - Port: 8999 (internal)                                     │
└─────────────────────────────────────────────────────────────┘
              │                               │
              ▼                               ▼
┌─────────────────────────┐   ┌─────────────────────────────┐
│  PostgreSQL              │   │  Redis                       │
│  - Persistent storage    │   │  - Session cache             │
│  - Port: 5432 (internal) │   │  - Port: 6379 (internal)     │
└─────────────────────────┘   └─────────────────────────────┘
```

---

## Production Deployment

The production environment adds horizontal scaling, network isolation, and stricter security.

### Prerequisites

1. A production server (recommended: 4+ CPU, 8GB+ RAM)
2. A domain name with DNS configured
3. Docker Swarm or Compose v2 for replicas

### Setup

```bash
# Copy environment template
cp .env.example .env

# Configure required variables
nano .env
```

Required environment variables:
```bash
DOMAIN=flowmason.example.com
ACME_EMAIL=admin@example.com
POSTGRES_PASSWORD=very-strong-password-here
REDIS_PASSWORD=very-strong-password-here
FLOWMASON_SECRETS_KEY=$(openssl rand -base64 32)
VERSION=1.0.0
```

### Deploy

```bash
# Start all services
docker-compose -f docker-compose.prod.yml up -d

# Scale Studio instances
docker-compose -f docker-compose.prod.yml up -d --scale studio=3

# View logs
docker-compose -f docker-compose.prod.yml logs -f studio
```

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                        Internet                              │
└─────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────┐
│  Traefik (Reverse Proxy)                                     │
│  - Production TLS with HSTS                                  │
│  - Security headers                                          │
│  - Load balancing                                            │
└─────────────────────────────────────────────────────────────┘
                              │
          ┌───────────────────┼───────────────────┐
          ▼                   ▼                   ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│  Studio #1      │ │  Studio #2      │ │  Studio #N      │
│  (replica)      │ │  (replica)      │ │  (replica)      │
└─────────────────┘ └─────────────────┘ └─────────────────┘
          │                   │                   │
          └───────────────────┼───────────────────┘
                              │
              ┌───────────────┴───────────────┐
              ▼                               ▼
┌─────────────────────────┐   ┌─────────────────────────────┐
│  PostgreSQL              │   │  Redis                       │
│  - Tuned for production  │   │  - LRU eviction              │
│  - Internal network only │   │  - Internal network only     │
└─────────────────────────┘   └─────────────────────────────┘
```

### Features

| Feature | Staging | Production |
|---------|---------|------------|
| Auto-SSL (Let's Encrypt) | Staging certs | Production certs |
| HSTS | No | Yes |
| Security headers | Basic | Full |
| Database | PostgreSQL | PostgreSQL (tuned) |
| Replicas | 1 | 2+ (configurable) |
| Network isolation | No | Yes (internal network) |
| Rolling updates | No | Yes |
| Resource limits | Basic | Strict |

### Security Considerations

1. **Required variables**: Production enforces required secrets
2. **Network isolation**: Database and Redis on internal-only network
3. **Auth required**: `FLOWMASON_REQUIRE_AUTH=true` by default
4. **Security headers**: HSTS, X-Content-Type-Options, X-XSS-Protection
5. **Non-root user**: Studio runs as non-root `flowmason` user

### Backup

```bash
# Backup PostgreSQL
docker-compose -f docker-compose.prod.yml exec postgres \
  pg_dump -U flowmason flowmason > backup.sql

# Backup Redis
docker-compose -f docker-compose.prod.yml exec redis \
  redis-cli -a $REDIS_PASSWORD BGSAVE
```

### Monitoring

```bash
# Container stats
docker stats

# Health check
curl -f https://flowmason.example.com/health

# Logs
docker-compose -f docker-compose.prod.yml logs -f --tail=100
```

---

## Image Versioning

For production, always pin to a specific version:

```bash
# Build with version tag
docker build -t flowmason/studio:1.0.0 .

# Use in docker-compose
VERSION=1.0.0 docker-compose -f docker-compose.prod.yml up -d
```

## Resource Recommendations

| Environment | CPU | Memory | Storage |
|-------------|-----|--------|---------|
| Local | 1 | 1GB | 5GB |
| Staging | 2 | 4GB | 20GB |
| Production | 4+ | 8GB+ | 50GB+ |


---

## 06-studio/overview.md

# FlowMason Studio

Studio is the backend server that provides REST APIs and real-time capabilities for FlowMason.

## Overview

Studio provides:
- REST API for pipeline management and execution
- WebSocket for real-time execution updates
- Debugging and testing endpoints
- Authentication and authorization
- Database storage for pipelines and runs

## Starting Studio

### From CLI

```bash
# Start with defaults
fm studio start

# Start on custom port
fm studio start --port 9000

# Check status
fm studio status

# Stop
fm studio stop

# Restart
fm studio restart
```

### From VSCode

- Command Palette > "FlowMason: Start Studio"
- Status bar shows connection status

### Programmatically

```python
from flowmason_studio.api.app import run_server

run_server(host="127.0.0.1", port=8999)
```

## API Endpoints

### Health Check

```
GET /health
```

Response:
```json
{
  "status": "healthy",
  "version": "0.1.0"
}
```

### Component Registry

```
GET /api/v1/registry/components
GET /api/v1/registry/components/{component_type}
GET /api/v1/registry/packages
POST /api/v1/registry/packages/install
DELETE /api/v1/registry/packages/{package_id}
```

### Pipelines

```
GET /api/v1/pipelines
GET /api/v1/pipelines/{pipeline_id}
POST /api/v1/pipelines
PUT /api/v1/pipelines/{pipeline_id}
DELETE /api/v1/pipelines/{pipeline_id}
POST /api/v1/pipelines/{pipeline_id}/clone
POST /api/v1/pipelines/{pipeline_id}/publish
POST /api/v1/pipelines/{pipeline_id}/unpublish
```

### Execution

```
POST /api/v1/run                           # Run pipeline by name (new)
POST /api/v1/runs
GET /api/v1/runs/{run_id}
GET /api/v1/runs/{run_id}/status
POST /api/v1/runs/{run_id}/pause
POST /api/v1/runs/{run_id}/resume
POST /api/v1/runs/{run_id}/step
POST /api/v1/runs/{run_id}/stop
POST /api/v1/runs/{run_id}/set-breakpoint
POST /api/v1/runs/{run_id}/clear-breakpoint
```

### Input/Output (New)

```
# Named Pipeline Invocation
POST /api/v1/run                           # Run by name: {"pipeline": "my-pipe@1.0.0"}

# Output Destination Allowlist
POST /api/v1/allowlist                     # Create allowlist entry
GET /api/v1/allowlist                      # List allowlist entries
PATCH /api/v1/allowlist/{id}               # Update entry
DELETE /api/v1/allowlist/{id}              # Delete entry
POST /api/v1/allowlist/validate            # Validate destination

# Stored Connections
POST /api/v1/connections                   # Create stored connection
GET /api/v1/connections                    # List connections
PATCH /api/v1/connections/{id}             # Update connection
DELETE /api/v1/connections/{id}            # Delete connection

# Delivery Logs
GET /api/v1/deliveries/{run_id}            # Get delivery log for run
```

See [Input/Output Architecture](api/input-output.md) for full documentation.

### Testing

```
POST /api/v1/tests/run
GET /api/v1/tests/{test_id}/status
GET /api/v1/tests/{test_id}/results
```

### Authentication

```
POST /api/v1/auth/api-keys
GET /api/v1/auth/api-keys
DELETE /api/v1/auth/api-keys/{key_id}
GET /api/v1/auth/me
```

### SAML/SSO

```
GET /api/v1/auth/saml/metadata/{org_id}
GET /api/v1/auth/saml/login/{org_id}
POST /api/v1/auth/saml/acs/{org_id}
GET /api/v1/auth/saml/config/{org_id}
PUT /api/v1/auth/saml/config/{org_id}
```

## WebSocket

Connect for real-time updates:

```
ws://localhost:8999/api/v1/ws/runs
```

### Protocol

**Subscribe to run:**
```json
{
  "type": "subscribe",
  "run_id": "run-abc123"
}
```

**Control commands:**
```json
{ "type": "pause", "run_id": "run-abc123" }
{ "type": "resume", "run_id": "run-abc123" }
{ "type": "step", "run_id": "run-abc123" }
```

### Events

| Event | Description |
|-------|-------------|
| `connected` | WebSocket connected |
| `subscribed` | Subscribed to run |
| `run_started` | Pipeline execution started |
| `stage_started` | Stage began |
| `stage_completed` | Stage finished |
| `stage_failed` | Stage error |
| `execution_paused` | Hit breakpoint |
| `run_completed` | Pipeline finished |
| `run_failed` | Pipeline error |
| `token_chunk` | LLM token received |
| `stream_start` | LLM streaming began |
| `stream_end` | LLM streaming ended |

## Authentication

### API Keys

```bash
# Create API key
curl -X POST http://localhost:8999/api/v1/auth/api-keys \
  -H "Content-Type: application/json" \
  -d '{"name": "my-key", "scopes": ["pipelines:read", "runs:write"]}'
```

### Using API Keys

```bash
curl -H "X-API-Key: fm_xxx" http://localhost:8999/api/v1/pipelines
```

### Scopes

| Scope | Description |
|-------|-------------|
| `pipelines:read` | Read pipelines |
| `pipelines:write` | Create/update pipelines |
| `runs:read` | Read execution data |
| `runs:write` | Execute pipelines |
| `registry:read` | Read components |
| `admin` | Full access |

## Database

### SQLite (Default)

```
.flowmason/flowmason.db
```

### PostgreSQL (Production)

Set environment variable:
```bash
DATABASE_URL=postgresql://user:pass@host:5432/flowmason
```

### Schema

Key tables:
- `pipelines` - Pipeline definitions (includes output_config)
- `runs` - Execution records
- `stages` - Stage execution details
- `organizations` - Multi-tenancy
- `users` - User accounts
- `api_keys` - API authentication
- `audit_log` - Security audit trail
- `output_allowlist` - Allowed output destinations per org
- `stored_connections` - Encrypted DB/MQ credentials
- `output_deliveries` - Output delivery logs

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `FLOWMASON_HOST` | `127.0.0.1` | Server host |
| `FLOWMASON_PORT` | `8999` | Server port |
| `DATABASE_URL` | SQLite | Database connection |
| `LOG_LEVEL` | `info` | Logging level |

### CORS

CORS is enabled by default for development. Configure in production:

```python
app = create_app(
    enable_cors=True,
    cors_origins=["https://app.example.com"]
)
```

## Examples

### Run a Pipeline

```python
import httpx

async def run_pipeline():
    async with httpx.AsyncClient() as client:
        # Create run
        response = await client.post(
            "http://localhost:8999/api/v1/runs",
            json={
                "pipeline_id": "my-pipeline",
                "input": {"url": "https://example.com"}
            }
        )
        run = response.json()
        run_id = run["run_id"]

        # Poll for completion
        while True:
            status = await client.get(
                f"http://localhost:8999/api/v1/runs/{run_id}/status"
            )
            if status.json()["status"] in ["completed", "failed"]:
                break
            await asyncio.sleep(0.5)

        # Get result
        result = await client.get(
            f"http://localhost:8999/api/v1/runs/{run_id}"
        )
        return result.json()
```

### WebSocket Client

```javascript
const ws = new WebSocket("ws://localhost:8999/api/v1/ws/runs");

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: "subscribe",
    run_id: "run-abc123"
  }));
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log(`Event: ${data.type}`, data);

  if (data.type === "stage_completed") {
    console.log(`Stage ${data.stage_id} completed`);
  }
};
```

## See Also

- [API Reference](api/rest-api.md) - Full API documentation
- [WebSocket Protocol](api/websocket.md) - Real-time communication
- [Authentication](../04-core-framework/auth.md) - Security details


---

## 06-studio/usage-tracking.md

# LLM Usage Tracking

FlowMason tracks token usage and costs across all LLM calls in your pipelines.

## Overview

Usage tracking provides:
- Per-run token usage and costs
- Aggregated usage by pipeline, provider, and model
- Daily usage trends
- Cost estimation for planning

## API Endpoints

### Get Usage Summary

```http
GET /api/v1/usage/summary?days=30
Authorization: Bearer <api-key>
```

Response:
```json
{
  "period_start": "2025-01-01T00:00:00",
  "period_end": "2025-01-31T00:00:00",
  "total_runs": 150,
  "total_stages": 450,
  "total_input_tokens": 1250000,
  "total_output_tokens": 320000,
  "total_tokens": 1570000,
  "total_cost_usd": 4.85,
  "by_provider": {
    "anthropic": {
      "input_tokens": 800000,
      "output_tokens": 200000,
      "total_tokens": 1000000,
      "cost_usd": 3.20,
      "request_count": 300
    },
    "openai": {
      "input_tokens": 450000,
      "output_tokens": 120000,
      "total_tokens": 570000,
      "cost_usd": 1.65,
      "request_count": 150
    }
  },
  "by_model": {
    "anthropic:claude-3-5-sonnet-20241022": {
      "provider": "anthropic",
      "model": "claude-3-5-sonnet-20241022",
      "input_tokens": 800000,
      "output_tokens": 200000,
      "cost_usd": 3.20,
      "request_count": 300
    }
  }
}
```

### Get Daily Usage

```http
GET /api/v1/usage/daily?days=7
Authorization: Bearer <api-key>
```

Response:
```json
[
  {
    "date": "2025-01-25",
    "run_count": 25,
    "stage_count": 75,
    "input_tokens": 180000,
    "output_tokens": 45000,
    "total_tokens": 225000,
    "cost_usd": 0.68
  },
  {
    "date": "2025-01-26",
    "run_count": 32,
    "stage_count": 96,
    "input_tokens": 210000,
    "output_tokens": 52000,
    "total_tokens": 262000,
    "cost_usd": 0.79
  }
]
```

### Get Run Usage

```http
GET /api/v1/usage/runs/{run_id}
Authorization: Bearer <api-key>
```

Response:
```json
{
  "run_id": "run-abc123",
  "total_input_tokens": 12500,
  "total_output_tokens": 3200,
  "total_tokens": 15700,
  "total_cost_usd": 0.048,
  "records": [
    {
      "id": "usage-xyz",
      "run_id": "run-abc123",
      "pipeline_id": "pipe-123",
      "stage_id": "generate-summary",
      "provider": "anthropic",
      "model": "claude-3-5-sonnet-20241022",
      "input_tokens": 8000,
      "output_tokens": 2000,
      "total_tokens": 10000,
      "cost_usd": 0.032,
      "duration_ms": 1250,
      "recorded_at": "2025-01-26T10:30:00Z"
    }
  ]
}
```

### Get Pricing

```http
GET /api/v1/usage/pricing
Authorization: Bearer <api-key>
```

Response:
```json
{
  "pricing": {
    "anthropic": {
      "claude-3-5-sonnet-20241022": {"input": 3.0, "output": 15.0},
      "claude-3-5-haiku-20241022": {"input": 1.0, "output": 5.0},
      "claude-3-opus-20240229": {"input": 15.0, "output": 75.0}
    },
    "openai": {
      "gpt-4o": {"input": 2.5, "output": 10.0},
      "gpt-4o-mini": {"input": 0.15, "output": 0.60}
    }
  },
  "updated_at": "2025-01-26T00:00:00Z"
}
```

Pricing is in USD per 1 million tokens.

### Estimate Cost

```http
GET /api/v1/usage/estimate?provider=anthropic&model=claude-3-5-sonnet-20241022&input_tokens=10000&output_tokens=2000
Authorization: Bearer <api-key>
```

Response:
```json
{
  "provider": "anthropic",
  "model": "claude-3-5-sonnet-20241022",
  "input_tokens": 10000,
  "output_tokens": 2000,
  "total_tokens": 12000,
  "pricing_per_million": {"input": 3.0, "output": 15.0},
  "estimated_cost": {
    "input_cost_usd": 0.03,
    "output_cost_usd": 0.03,
    "total_cost_usd": 0.06
  }
}
```

## Query Parameters

| Parameter | Description | Default |
|-----------|-------------|---------|
| `days` | Number of days to include | 30 |
| `pipeline_id` | Filter by pipeline | All pipelines |
| `include_by_pipeline` | Include breakdown by pipeline | false |

## Supported Providers

Usage is automatically tracked for all supported LLM providers:

| Provider | Models |
|----------|--------|
| Anthropic | Claude 3.5 Sonnet, Claude 3.5 Haiku, Claude 3 Opus, Claude 3 Sonnet, Claude 3 Haiku |
| OpenAI | GPT-4o, GPT-4o-mini, GPT-4 Turbo, GPT-4, GPT-3.5 Turbo |
| Google | Gemini 1.5 Pro, Gemini 1.5 Flash, Gemini 2.0 Flash |
| Groq | Llama 3.3 70B, Llama 3.1 70B, Mixtral 8x7B |

## How It Works

1. When a pipeline stage makes an LLM call, the provider returns token counts
2. FlowMason records the usage with provider, model, and token counts
3. Cost is calculated based on current pricing
4. Data is aggregated daily for fast queries

## Data Retention

- Detailed per-stage records: 90 days
- Daily aggregates: 1 year
- Summary statistics: Indefinite

## Use Cases

### Cost Optimization

Compare costs across models:

```http
GET /api/v1/usage/summary?days=30&include_by_pipeline=true
```

Identify expensive pipelines and consider:
- Using smaller models for simpler tasks
- Caching common queries
- Batching similar requests

### Budget Monitoring

Track daily spend against budget:

```http
GET /api/v1/usage/daily?days=30
```

### Cost Estimation

Before deploying a pipeline, estimate costs:

```http
GET /api/v1/usage/estimate?provider=anthropic&model=claude-3-5-sonnet-20241022&input_tokens=100000&output_tokens=20000
```

## Best Practices

1. **Choose the right model**: Use smaller models (Haiku, GPT-4o-mini) for simple tasks
2. **Monitor trends**: Watch for unexpected cost increases
3. **Set alerts**: Create webhook triggers for high usage thresholds
4. **Cache when possible**: Use the `memory` operator to cache repeated queries
5. **Batch requests**: Group similar requests to reduce overhead


---

## 06-studio/webhooks.md

# Webhook Triggers

FlowMason allows external systems to trigger pipeline executions via HTTP webhooks.

## Overview

Webhooks provide a way to:
- Trigger pipelines from external services (GitHub, Slack, Stripe, etc.)
- Build event-driven automation workflows
- Integrate FlowMason with CI/CD pipelines
- Create public APIs backed by FlowMason pipelines

## Creating a Webhook

### Via API

```http
POST /api/v1/webhooks
Authorization: Bearer <api-key>
Content-Type: application/json

{
  "name": "GitHub Push Handler",
  "pipeline_id": "my-pipeline-id",
  "input_mapping": {
    "repository.full_name": "repo",
    "commits": "commits",
    "pusher.name": "author"
  },
  "default_inputs": {
    "environment": "production"
  },
  "require_auth": true,
  "auth_header": "X-Hub-Signature-256",
  "auth_secret": "my-webhook-secret",
  "async_mode": true,
  "description": "Handles GitHub push events"
}
```

Response:
```json
{
  "id": "wh-abc123",
  "name": "GitHub Push Handler",
  "pipeline_id": "my-pipeline-id",
  "webhook_url": "https://studio.example.com/api/v1/webhook/aBcDeFgHiJkLmNoPqRsTuVwXyZ",
  "enabled": true,
  "require_auth": true,
  "auth_header": "X-Hub-Signature-256",
  "async_mode": true,
  "trigger_count": 0
}
```

## Triggering a Webhook

Once created, the webhook can be called from any HTTP client:

```bash
curl -X POST https://studio.example.com/api/v1/webhook/aBcDeFgHiJkLmNoPqRsTuVwXyZ \
  -H "Content-Type: application/json" \
  -H "X-Hub-Signature-256: my-webhook-secret" \
  -d '{"repository": {"full_name": "user/repo"}, "commits": [...]}'
```

### Async Mode (Default)

Returns immediately with a run ID:

```json
{
  "status": "accepted",
  "message": "Pipeline execution started",
  "run_id": "run-xyz789"
}
```

### Sync Mode

When `async_mode: false`, waits for pipeline completion:

```json
{
  "status": "completed",
  "message": "Pipeline execution completed",
  "run_id": "run-xyz789",
  "result": { ... }
}
```

## Input Mapping

Map fields from the webhook payload to pipeline inputs using dot notation:

| Webhook Payload | Input Mapping | Pipeline Input |
|-----------------|---------------|----------------|
| `{"user": {"id": 123}}` | `"user.id": "userId"` | `{"userId": 123}` |
| `{"items": [1, 2, 3]}` | `"items": "data"` | `{"data": [1, 2, 3]}` |
| `{"event": "push"}` | `"event": "action"` | `{"action": "push"}` |

### Default Inputs

Provide fallback values for pipeline inputs:

```json
{
  "default_inputs": {
    "environment": "production",
    "notify": true,
    "retries": 3
  }
}
```

### No Mapping (Pass-Through)

If `input_mapping` is empty, the entire webhook payload is passed as pipeline input.

## Authentication

### Secret Header

```json
{
  "require_auth": true,
  "auth_header": "X-Webhook-Secret",
  "auth_secret": "my-secret-value"
}
```

Requests must include:
```http
X-Webhook-Secret: my-secret-value
```

### Common Integrations

| Service | Auth Header | Documentation |
|---------|-------------|---------------|
| GitHub | `X-Hub-Signature-256` | [GitHub Webhooks](https://docs.github.com/webhooks) |
| Stripe | `Stripe-Signature` | [Stripe Webhooks](https://stripe.com/docs/webhooks) |
| Slack | `X-Slack-Signature` | [Slack Events](https://api.slack.com/events) |

### No Authentication

For testing or internal use:
```json
{
  "require_auth": false
}
```

## Management Endpoints

### List Webhooks

```http
GET /api/v1/webhooks
```

### Get Webhook

```http
GET /api/v1/webhooks/{webhook_id}
```

### Update Webhook

```http
PUT /api/v1/webhooks/{webhook_id}
```

### Delete Webhook

```http
DELETE /api/v1/webhooks/{webhook_id}
```

### Regenerate Token

Invalidates the old webhook URL:

```http
POST /api/v1/webhooks/{webhook_id}/regenerate-token
```

### Get Invocation History

```http
GET /api/v1/webhooks/{webhook_id}/invocations
```

## Invocation Logging

All webhook calls are logged:

```json
{
  "id": "inv-123",
  "webhook_id": "wh-abc123",
  "run_id": "run-xyz789",
  "status": "success",
  "invoked_at": "2025-01-15T10:30:00Z"
}
```

Status values:
- `success`: Webhook processed, pipeline started
- `rejected`: Authentication failed or webhook disabled
- `error`: Processing error (invalid payload, pipeline not found)

## Example: GitHub CI Integration

1. Create webhook:
```json
{
  "name": "Deploy on Push to Main",
  "pipeline_id": "deploy-pipeline",
  "input_mapping": {
    "ref": "branch",
    "repository.full_name": "repo",
    "head_commit.message": "commit_message"
  },
  "auth_header": "X-Hub-Signature-256",
  "auth_secret": "github-webhook-secret"
}
```

2. Configure in GitHub:
   - Payload URL: Copy webhook_url from response
   - Content type: `application/json`
   - Secret: `github-webhook-secret`
   - Events: Push events

3. Pipeline receives:
```json
{
  "branch": "refs/heads/main",
  "repo": "user/my-app",
  "commit_message": "Fix bug in login"
}
```

## Example: Stripe Payment Handler

```json
{
  "name": "Process Stripe Payment",
  "pipeline_id": "payment-processor",
  "input_mapping": {
    "type": "event_type",
    "data.object.id": "payment_id",
    "data.object.amount": "amount",
    "data.object.customer": "customer_id"
  },
  "async_mode": false
}
```

## Security Best Practices

1. **Always use authentication** in production
2. **Validate webhook signatures** for external services
3. **Use HTTPS** for webhook URLs
4. **Regenerate tokens** if compromised
5. **Monitor invocation logs** for suspicious activity
6. **Set appropriate timeouts** for sync mode

## Troubleshooting

### Webhook Not Triggering

1. Check if webhook is enabled
2. Verify the token in the URL
3. Check authentication header/value
4. Review invocation logs for errors

### Invalid Payload Error

1. Ensure Content-Type is `application/json`
2. Validate JSON syntax
3. Check input_mapping paths exist in payload

### Authentication Failed

1. Verify auth_header name matches request
2. Confirm auth_secret matches configured value
3. Check for extra whitespace in header value


---

## 07-integrations/mcp-client-operators.md

# MCP Client Operators

FlowMason provides operators to call tools from MCP (Model Context Protocol) servers, enabling pipelines to leverage external AI tools and services.

## Overview

MCP client operators allow pipelines to:
- Discover available tools from MCP servers
- Call specific tools with arguments
- Process tool responses in pipeline stages

## Available Operators

### mcp_tool_call

Call a tool from an MCP server.

```json
{
  "id": "call-tool",
  "component_type": "mcp_tool_call",
  "config": {
    "transport": "stdio",
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"],
    "tool_name": "read_file",
    "tool_arguments": {
      "path": "/data/config.json"
    }
  }
}
```

#### Input Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `transport` | "stdio" \| "sse" | No | Transport type (default: "stdio") |
| `command` | string | For stdio | Command to start MCP server |
| `args` | list | No | Command arguments |
| `env` | object | No | Environment variables |
| `url` | string | For sse | URL of MCP SSE server |
| `tool_name` | string | Yes | Name of the tool to call |
| `tool_arguments` | object | No | Arguments to pass to the tool |
| `timeout` | int | No | Timeout in seconds (default: 30) |

#### Output Fields

| Field | Type | Description |
|-------|------|-------------|
| `content` | any | Tool response content |
| `is_error` | bool | True if the tool returned an error |
| `error_message` | string | Error message if is_error is true |
| `tool_name` | string | Name of the tool called |
| `elapsed_ms` | int | Execution time in milliseconds |

### mcp_list_tools

Discover available tools from an MCP server.

```json
{
  "id": "discover-tools",
  "component_type": "mcp_list_tools",
  "config": {
    "transport": "stdio",
    "command": "npx",
    "args": ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
  }
}
```

#### Input Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `transport` | "stdio" \| "sse" | No | Transport type (default: "stdio") |
| `command` | string | For stdio | Command to start MCP server |
| `args` | list | No | Command arguments |
| `env` | object | No | Environment variables |
| `url` | string | For sse | URL of MCP SSE server |
| `timeout` | int | No | Timeout in seconds (default: 30) |

#### Output Fields

| Field | Type | Description |
|-------|------|-------------|
| `tools` | list | List of available tools |
| `tool_count` | int | Number of available tools |
| `server_name` | string | Name of the MCP server |
| `server_version` | string | Version of the MCP server |

## Transport Types

### stdio (Process Communication)

Launch an MCP server process and communicate via stdin/stdout:

```json
{
  "transport": "stdio",
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-github"],
  "env": {"GITHUB_TOKEN": "{{secrets.GITHUB_TOKEN}}"}
}
```

Commonly used with:
- NPM packages: `npx -y @modelcontextprotocol/server-*`
- Python servers: `python -m mcp_server_name`
- Node.js scripts: `node /path/to/server.js`

### sse (HTTP Server-Sent Events)

Connect to an MCP server running as an HTTP service:

```json
{
  "transport": "sse",
  "url": "http://mcp-server.example.com:8080"
}
```

Useful for:
- Remote MCP servers
- Shared infrastructure
- High-availability deployments

## Example Pipelines

### File Operations

Read and process files using the filesystem MCP server:

```json
{
  "name": "file-processor",
  "stages": [
    {
      "id": "read-config",
      "component_type": "mcp_tool_call",
      "config": {
        "transport": "stdio",
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-filesystem", "/app"],
        "tool_name": "read_file",
        "tool_arguments": {"path": "/app/config.json"}
      }
    },
    {
      "id": "process-config",
      "component_type": "json_transform",
      "depends_on": ["read-config"],
      "config": {
        "expression": "$.config | parse_json"
      }
    }
  ]
}
```

### GitHub Integration

Query GitHub repositories using the GitHub MCP server:

```json
{
  "name": "github-analyzer",
  "stages": [
    {
      "id": "list-issues",
      "component_type": "mcp_tool_call",
      "config": {
        "transport": "stdio",
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-github"],
        "env": {"GITHUB_TOKEN": "{{secrets.GITHUB_TOKEN}}"},
        "tool_name": "list_issues",
        "tool_arguments": {
          "owner": "anthropics",
          "repo": "claude-code",
          "state": "open"
        }
      }
    }
  ]
}
```

### Database Queries

Query databases using the Postgres MCP server:

```json
{
  "name": "data-pipeline",
  "stages": [
    {
      "id": "query-users",
      "component_type": "mcp_tool_call",
      "config": {
        "transport": "stdio",
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-postgres"],
        "env": {"DATABASE_URL": "{{secrets.DATABASE_URL}}"},
        "tool_name": "query",
        "tool_arguments": {
          "sql": "SELECT * FROM users WHERE active = true LIMIT 100"
        }
      }
    }
  ]
}
```

### Dynamic Tool Discovery

Discover available tools and call them dynamically:

```json
{
  "name": "tool-explorer",
  "stages": [
    {
      "id": "list-available-tools",
      "component_type": "mcp_list_tools",
      "config": {
        "transport": "stdio",
        "command": "npx",
        "args": ["-y", "@modelcontextprotocol/server-everything"]
      }
    },
    {
      "id": "select-tool",
      "component_type": "router",
      "depends_on": ["list-available-tools"],
      "config": {
        "routes": [
          {"condition": "search in $.tools[*].name", "next_stage": "call-search"},
          {"default": true, "next_stage": "no-search"}
        ]
      }
    }
  ]
}
```

## Installation

MCP operators require the `mcp` package:

```bash
pip install flowmason[mcp]
# or
pip install mcp
```

## Popular MCP Servers

| Server | NPM Package | Description |
|--------|-------------|-------------|
| Filesystem | `@modelcontextprotocol/server-filesystem` | File read/write operations |
| GitHub | `@modelcontextprotocol/server-github` | GitHub API integration |
| Postgres | `@modelcontextprotocol/server-postgres` | PostgreSQL queries |
| Brave Search | `@modelcontextprotocol/server-brave-search` | Web search |
| Memory | `@modelcontextprotocol/server-memory` | Key-value storage |
| Puppeteer | `@modelcontextprotocol/server-puppeteer` | Browser automation |

See [MCP Servers](https://modelcontextprotocol.io/servers) for more options.

## Error Handling

Handle tool errors in your pipeline:

```json
{
  "stages": [
    {
      "id": "call-tool",
      "component_type": "mcp_tool_call",
      "config": {"..."}
    },
    {
      "id": "handle-result",
      "component_type": "conditional",
      "depends_on": ["call-tool"],
      "config": {
        "condition": "$.is_error == false",
        "true_stage": "process-success",
        "false_stage": "handle-error"
      }
    }
  ]
}
```

## Best Practices

1. **Use secrets for credentials**: Store API keys and tokens in FlowMason secrets
2. **Set appropriate timeouts**: MCP calls can be slow; set realistic timeouts
3. **Handle errors gracefully**: Check `is_error` in downstream stages
4. **Discover before calling**: Use `mcp_list_tools` to validate tool availability
5. **Use SSE for production**: stdio transport creates new processes; SSE is more efficient


---

## 07-integrations/mcp-server.md

# MCP Server Integration

FlowMason includes a Model Context Protocol (MCP) server that exposes pipelines to AI assistants like Claude.

## Overview

The MCP server allows AI assistants to:
- List available pipelines
- Get detailed pipeline information
- Execute pipelines with input data
- Browse available components

## Installation

Install with MCP support:

```bash
pip install flowmason[mcp]
```

Or install the MCP SDK separately:

```bash
pip install mcp
```

## Quick Start

Start the MCP server:

```bash
fm mcp serve
```

With custom options:

```bash
fm mcp serve --pipelines ./my-pipelines --studio-url http://localhost:8999
```

## Claude Desktop Configuration

To use FlowMason with Claude Desktop:

1. Get the configuration:
   ```bash
   fm mcp config
   ```

2. Add the configuration to your Claude Desktop config file:
   - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`

Example configuration:

```json
{
  "mcpServers": {
    "flowmason": {
      "command": "python",
      "args": ["-m", "flowmason_core.cli.main", "mcp", "serve"],
      "env": {
        "PYTHONUNBUFFERED": "1"
      }
    }
  }
}
```

3. Restart Claude Desktop

## Available Tools

### list_pipelines

Lists all available FlowMason pipelines with their names, descriptions, and stage counts.

**Example prompt:**
> "Show me available FlowMason pipelines"

### get_pipeline

Gets detailed information about a specific pipeline including its input schema and stages.

**Arguments:**
- `pipeline_name`: Name of the pipeline

**Example prompt:**
> "Show me the details of the data-validation-etl pipeline"

### run_pipeline

Executes a pipeline with optional input data.

**Arguments:**
- `pipeline_name`: Name of the pipeline to run
- `input_data`: JSON string with input data (optional)

**Example prompt:**
> "Run the batch-processing pipeline with items: [{'id': '1', 'value': 100}]"

### list_components

Lists all available FlowMason components (operators and nodes).

**Example prompt:**
> "What components are available in FlowMason?"

### get_component

Gets detailed information about a specific component including its configuration schema.

**Arguments:**
- `component_type`: The component type (e.g., 'generator', 'json_transform')

**Example prompt:**
> "Tell me about the json_transform component"

## Requirements

- FlowMason Studio must be running for pipeline execution
- Pipelines should be in the configured directory or uploaded to Studio

## Testing

Test the MCP server:

```bash
fm mcp test
```

This verifies that the server can be created and lists available tools.

## Troubleshooting

### "Cannot connect to FlowMason Studio"

Start the Studio server:
```bash
fm studio start
```

### "MCP SDK not installed"

Install the MCP dependency:
```bash
pip install flowmason[mcp]
```

### "No pipelines found"

Ensure pipelines are in the correct directory or use `--pipelines` to specify the location.


---

## 07-vscode-extension/overview.md

# VSCode Extension Overview

The FlowMason VSCode extension provides a native IDE experience for building, debugging, and testing AI pipelines.

## Installation

```bash
# From VSIX file
code --install-extension flowmason-0.10.0.vsix

# Or from source
cd vscode-extension
npm install && npm run compile && npm run package
code --install-extension flowmason-0.10.0.vsix
```

## Features Overview

### Language Support

| Feature | Description |
|---------|-------------|
| **IntelliSense** | Autocomplete for decorators, components, configs |
| **Diagnostics** | Real-time validation and error highlighting |
| **Hover** | Documentation on hover for components |
| **CodeLens** | Run/Preview buttons above decorators |
| **Go to Definition** | Jump to component definitions (F12) |
| **Find References** | Find all usages of components |
| **Document Symbols** | Outline view for pipeline structure |

### Pipeline Editing

| Feature | Description |
|---------|-------------|
| **DAG Canvas** | Visual editor for pipeline stages |
| **Stage Tree** | Tree view of pipeline stages |
| **Config Panel** | Edit stage configuration in sidebar |
| **Validation** | Real-time pipeline validation |

### Debugging (DAP)

| Feature | Description |
|---------|-------------|
| **Breakpoints** | Set breakpoints on stages (F9) |
| **Step Through** | Step over stages (F10) |
| **Variables** | Inspect inputs/outputs in panel |
| **Prompt Editor** | Edit prompts during debug |
| **Token Streaming** | See LLM tokens in real-time |

### Testing

| Feature | Description |
|---------|-------------|
| **Test Explorer** | VSCode Test Explorer integration |
| **Test Discovery** | Auto-discover `.test.json` files |
| **Coverage** | Code coverage reporting |

## Getting Started

### 1. Open a FlowMason Project

```bash
cd my-flowmason-project
code .
```

The extension activates automatically when it detects `flowmason.json`.

### 2. Start Studio

Use Command Palette (Cmd+Shift+P):
- "FlowMason: Start Studio" - Start the backend server
- "FlowMason: Stop Studio" - Stop the server
- "FlowMason: Restart Studio" - Restart the server

Or use the status bar button.

### 3. Create a Pipeline

1. Right-click in Explorer > "New FlowMason Pipeline"
2. Enter pipeline name
3. Opens in DAG Canvas editor

Or create manually:
```json
// pipelines/my-pipeline.pipeline.json
{
  "name": "my-pipeline",
  "version": "1.0.0",
  "stages": []
}
```

### 4. Add Stages

In the DAG Canvas:
1. Click "Add Stage" or use Cmd+Shift+A
2. Select component from QuickPick
3. Configure in the sidebar panel

### 5. Run Pipeline

- Press `F5` to run with debugging
- Press `Ctrl+F5` to run without debugging
- Click the "Run" CodeLens above the pipeline

### 6. Debug Pipeline

1. Set breakpoints (F9 on a stage)
2. Press F5 to start debugging
3. Use F10 to step through
4. Inspect variables in the Debug panel
5. Edit prompts in the Prompt Editor panel

## Views

### Activity Bar

The FlowMason activity bar icon reveals:

```
FLOWMASON
├── Components
│   ├── Nodes
│   │   ├── generator
│   │   ├── critic
│   │   └── ...
│   ├── Operators
│   │   ├── http-request
│   │   └── ...
│   └── Control Flow
│       ├── conditional
│       └── ...
├── Pipelines
│   ├── main.pipeline.json
│   └── etl.pipeline.json
├── Runs
│   ├── run-abc123 (completed)
│   └── run-def456 (running)
└── Tests
    └── main.test.json
```

### Pipeline Stages View

When a `.pipeline.json` file is open:

```
PIPELINE STAGES
├── fetch (http-request)
├── process (json-transform)
├── generate (generator)
└── output (logger)
```

Click a stage to:
- Select it in the DAG Canvas
- Open configuration in sidebar

### Stage Config View

Sidebar panel showing:
- Stage ID and component type
- Input configuration fields
- Dependencies
- Apply/Reset buttons

## Commands

| Command | Keybinding | Description |
|---------|------------|-------------|
| FlowMason: Start Studio | - | Start backend server |
| FlowMason: Stop Studio | - | Stop backend server |
| FlowMason: Run Pipeline | F5 | Run current pipeline |
| FlowMason: Debug Pipeline | Ctrl+F5 | Debug with breakpoints |
| FlowMason: Toggle Breakpoint | F9 | Add/remove stage breakpoint |
| FlowMason: Step Over | F10 | Step to next stage |
| FlowMason: Continue | F5 | Continue to next breakpoint |
| FlowMason: Stop | Shift+F5 | Stop execution |
| FlowMason: Add Stage | Cmd+Shift+A | Add stage to pipeline |
| FlowMason: Open DAG View | - | Open visual editor |
| FlowMason: Preview Component | - | Preview component output |
| FlowMason: New Node | - | Scaffold new node |
| FlowMason: New Operator | - | Scaffold new operator |
| FlowMason: Run Tests | Cmd+; A | Run all tests |

## Settings

Configure in VSCode Settings (Cmd+,):

```json
{
  "flowmason.studioHost": "localhost",
  "flowmason.studioPort": 8999,
  "flowmason.autoStartStudio": true,
  "flowmason.showCodeLens": true,
  "flowmason.diagnostics.enabled": true,
  "flowmason.debugger.showTokenStream": true
}
```

| Setting | Default | Description |
|---------|---------|-------------|
| `studioHost` | `localhost` | Studio server host |
| `studioPort` | `8999` | Studio server port |
| `autoStartStudio` | `true` | Auto-start Studio on activation |
| `showCodeLens` | `true` | Show Run/Preview buttons |
| `diagnostics.enabled` | `true` | Enable validation diagnostics |
| `debugger.showTokenStream` | `true` | Show tokens during debug |

## Debug Configuration

Create `.vscode/launch.json`:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug Pipeline",
      "pipeline": "${file}",
      "input": {
        "name": "test"
      },
      "stopOnEntry": false,
      "breakOnException": true
    }
  ]
}
```

| Property | Description |
|----------|-------------|
| `pipeline` | Pipeline file path |
| `input` | Input data for pipeline |
| `inputFile` | JSON file with input data |
| `stopOnEntry` | Break on first stage |
| `breakOnException` | Break on errors |

## Test Explorer

### Test File Format

Create `.test.json` files:

```json
{
  "name": "Pipeline Tests",
  "pipeline": "pipelines/main.pipeline.json",
  "tests": [
    {
      "name": "happy path",
      "input": { "url": "https://example.com" },
      "assertions": [
        { "path": "output.status", "equals": "success" }
      ]
    }
  ]
}
```

### Running Tests

- Click "Run" button in Test Explorer
- Use Cmd+; A to run all tests
- Right-click test > "Run Test"

### Coverage

Coverage reports appear in:
- Test Explorer (per-file coverage)
- Editor gutters (line coverage)
- Coverage panel (summary)

## Prompt Editor

During debugging, the Prompt Editor panel shows:

1. **Current Prompt**: System and user prompts being sent
2. **Edit Mode**: Modify prompts live
3. **Re-run**: Execute stage with modified prompt
4. **Compare**: Side-by-side output comparison
5. **History**: Previous prompt versions
6. **Streaming**: Watch tokens arrive in real-time

### Workflow

1. Set breakpoint on LLM stage
2. Start debugging (F5)
3. When paused, open Prompt Editor
4. Edit the prompt
5. Click "Re-run Stage"
6. Compare outputs
7. Save successful prompt as new version

## Status Bar

The status bar shows:
- Studio connection status (green/red dot)
- Current pipeline name
- Run status (Ready/Running/Paused)
- Click to access quick actions

## Troubleshooting

### Studio Won't Start

```bash
# Check if port is in use
lsof -i :8999

# Start manually
fm studio start --port 8999
```

### Extension Not Activating

- Ensure `flowmason.json` exists in workspace
- Check Output panel > "FlowMason" for errors
- Reload window (Cmd+Shift+P > "Reload Window")

### Debug Session Fails

- Ensure Studio is running
- Check pipeline is valid (`fm validate`)
- Check API keys are set

## See Also

- [Debugging Guide](../09-debugging-testing/debugging/current-debugging.md)
- [Testing Guide](../09-debugging-testing/testing/pipeline-testing.md)
- [Getting Started](../02-getting-started/quickstart.md)


---

## 08-packaging-deployment/distribution-strategy.md

# FlowMason Distribution Strategy

This guide covers distributing FlowMason as a **closed-source** product across three channels.

## Overview

| Component | Channel | Install Command |
|-----------|---------|-----------------|
| **VSCode Extension** | VS Code Marketplace | Install from Extensions panel |
| **Local Runtime** | PyPI | `pip install flowmason` |
| **Production Runtime** | Docker Hub | `docker pull flowmason/studio:0.4.0` |

```
┌─────────────────────────────────────────────────────────────────────┐
│                        DISTRIBUTION                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   VSCode Extension          Python Runtime         Docker Images    │
│   ┌─────────────┐          ┌─────────────┐        ┌─────────────┐  │
│   │ Marketplace │          │    PyPI     │        │ Docker Hub  │  │
│   │             │          │             │        │             │  │
│   │ .vsix       │          │ .whl        │        │ Image       │  │
│   └──────┬──────┘          └──────┬──────┘        └──────┬──────┘  │
│          │                        │                      │         │
│          ▼                        ▼                      ▼         │
│   code --install           pip install            docker pull      │
│   flowmason                flowmason              flowmason/studio │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘
```

---

## 1. VSCode Extension → VS Code Marketplace

### Prerequisites

1. **Microsoft/Azure Account**
   - Go to [https://marketplace.visualstudio.com/manage](https://marketplace.visualstudio.com/manage)
   - Sign in with Microsoft account

2. **Create Publisher**
   - Click "Create Publisher"
   - Publisher ID: `flowmason` (used in extension ID)
   - Display Name: `FlowMason`

3. **Personal Access Token (PAT)**
   - Go to [Azure DevOps](https://dev.azure.com/)
   - User Settings → Personal Access Tokens
   - Create token with **Marketplace (Manage)** scope
   - Save the token securely

### Update package.json

```json
{
  "name": "flowmason",
  "displayName": "FlowMason",
  "description": "AI Pipeline Development for VSCode",
  "version": "0.4.0",
  "publisher": "flowmason",
  "icon": "images/icon.png",
  "repository": {
    "type": "git",
    "url": "https://flowmason.com"
  },
  "homepage": "https://flowmason.com",
  "bugs": {
    "url": "https://flowmason.com/support"
  }
}
```

**Note:** `repository` URL doesn't need to be a real Git repo - can be your website.

### Build and Publish

```bash
cd vscode-extension

# Install vsce (VS Code Extension manager)
npm install -g @vscode/vsce

# Login with your PAT
vsce login flowmason

# Package (creates .vsix)
vsce package

# Publish to Marketplace
vsce publish
```

### Verify Publication

1. Go to [VS Code Marketplace](https://marketplace.visualstudio.com/)
2. Search for "FlowMason"
3. Your extension should appear

### Users Install Via

- **VSCode UI**: Extensions panel → Search "FlowMason" → Install
- **Command**: `code --install-extension flowmason.flowmason`

---

## 2. Python Runtime → PyPI (Closed Source)

### Prerequisites

1. **PyPI Account**: [https://pypi.org/account/register/](https://pypi.org/account/register/)
2. **API Token**: [https://pypi.org/manage/account/token/](https://pypi.org/manage/account/token/)
3. **Build Tools**: `pip install build twine`

### Configure pyproject.toml

```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "flowmason"
version = "0.4.0"
description = "Universal AI Workflow Infrastructure"
readme = "README.md"
requires-python = ">=3.11"
license = "Proprietary"
authors = [
    { name = "FlowMason", email = "support@flowmason.com" }
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: Other/Proprietary License",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
]
dependencies = [
    "pydantic>=2.0.0",
    "fastapi>=0.109.0",
    "uvicorn[standard]>=0.27.0",
    "typer>=0.9.0",
    "rich>=13.0.0",
    "httpx>=0.26.0",
]

[project.urls]
Homepage = "https://flowmason.com"
Documentation = "https://flowmason.com/docs"
Support = "https://flowmason.com/support"

[project.scripts]
flowmason = "flowmason_core.cli.main:cli"
fm = "flowmason_core.cli.main:cli"

[tool.hatch.build.targets.wheel]
packages = ["core/flowmason_core", "studio/flowmason_studio", "lab/flowmason_lab"]
```

**Key Points:**
- `license = "Proprietary"` - Indicates closed source
- `License :: Other/Proprietary License` - PyPI classifier
- No repository URL required

### Create README.md for PyPI

```markdown
# FlowMason

Universal AI Workflow Infrastructure for building, debugging, and deploying intelligent pipelines.

## Installation

```bash
pip install flowmason
```

## Quick Start

```bash
# Initialize a project
fm init

# Start the Studio backend
fm studio start

# Run a pipeline
fm run pipelines/main.pipeline.json
```

## Documentation

Visit [https://flowmason.com/docs](https://flowmason.com/docs)

## Support

- Documentation: https://flowmason.com/docs
- Support: https://flowmason.com/support
- Email: support@flowmason.com

## License

Proprietary. See LICENSE file for terms.
```

### Create LICENSE File

```
FlowMason Proprietary License

Copyright (c) 2025 FlowMason

All rights reserved.

This software and associated documentation files (the "Software") are proprietary
and confidential. Unauthorized copying, modification, distribution, or use of
this Software, via any medium, is strictly prohibited.

The Software is provided "as is", without warranty of any kind, express or implied.

For licensing inquiries, contact: licensing@flowmason.com
```

### Build and Publish

```bash
cd /path/to/flowmason

# Clean previous builds
rm -rf dist/ build/ *.egg-info

# Build wheel only (no source distribution)
python -m build --wheel

# Verify
twine check dist/*

# Publish
twine upload dist/*
# Username: __token__
# Password: pypi-your-api-token
```

### Users Install Via

```bash
pip install flowmason
```

---

## 3. Production Runtime → Docker Hub

### Prerequisites

1. **Docker Hub Account**: [https://hub.docker.com/signup](https://hub.docker.com/signup)
2. **Create Repository**: `flowmason/studio`
3. **Docker Installed**: For building images

### Create Dockerfile

`docker/Dockerfile.studio`:

```dockerfile
FROM python:3.11-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Copy and install Python package
COPY dist/flowmason-*.whl /tmp/
RUN pip install --no-cache-dir /tmp/flowmason-*.whl && rm /tmp/*.whl

# Create non-root user
RUN useradd -m -u 1000 flowmason
USER flowmason

# Expose port
EXPOSE 8999

# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
    CMD curl -f http://localhost:8999/health || exit 1

# Start Studio
CMD ["fm", "studio", "start", "--host", "0.0.0.0", "--port", "8999"]
```

### Build and Push

```bash
# Build Python wheel first
python -m build --wheel

# Build Docker image
docker build -f docker/Dockerfile.studio -t flowmason/studio:0.4.0 .
docker tag flowmason/studio:0.4.0 flowmason/studio:latest

# Login to Docker Hub
docker login

# Push images
docker push flowmason/studio:0.4.0
docker push flowmason/studio:latest
```

### Docker Compose for Users

Create `docker-compose.yml` for documentation:

```yaml
version: '3.8'

services:
  studio:
    image: flowmason/studio:0.4.0
    ports:
      - "8999:8999"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/flowmason
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=flowmason
    volumes:
      - flowmason_data:/var/lib/postgresql/data
    restart: unless-stopped

volumes:
  flowmason_data:
```

### Users Deploy Via

```bash
# Simple
docker pull flowmason/studio:0.4.0
docker run -p 8999:8999 flowmason/studio:0.4.0

# Production
docker-compose up -d
```

---

## CI/CD Automation

### GitHub Actions (Private Repo)

`.github/workflows/release.yml`:

```yaml
name: Release

on:
  push:
    tags:
      - 'v*'

jobs:
  # Build and publish Python package
  publish-pypi:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install build tools
        run: pip install build twine

      - name: Build wheel
        run: python -m build --wheel

      - name: Publish to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: twine upload dist/*

  # Build and publish Docker image
  publish-docker:
    runs-on: ubuntu-latest
    needs: publish-pypi
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Build wheel
        run: |
          pip install build
          python -m build --wheel

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Extract version
        id: version
        run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          file: docker/Dockerfile.studio
          push: true
          tags: |
            flowmason/studio:${{ steps.version.outputs.VERSION }}
            flowmason/studio:latest

  # Publish VSCode extension
  publish-vscode:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'

      - name: Install dependencies
        working-directory: vscode-extension
        run: npm install

      - name: Publish to Marketplace
        working-directory: vscode-extension
        env:
          VSCE_PAT: ${{ secrets.VSCE_PAT }}
        run: |
          npm install -g @vscode/vsce
          vsce publish -p $VSCE_PAT
```

### Required Secrets

Add to GitHub repository Settings → Secrets:

| Secret | Description |
|--------|-------------|
| `PYPI_API_TOKEN` | PyPI API token |
| `DOCKERHUB_USERNAME` | Docker Hub username |
| `DOCKERHUB_TOKEN` | Docker Hub access token |
| `VSCE_PAT` | VS Code Marketplace PAT |

---

## Release Checklist

- [ ] Update version in:
  - [ ] `pyproject.toml`
  - [ ] `vscode-extension/package.json`
  - [ ] `docker/Dockerfile.studio` (if hardcoded)
- [ ] Update CHANGELOG
- [ ] Test locally:
  - [ ] `pip install dist/*.whl`
  - [ ] `code --install-extension *.vsix`
  - [ ] `docker build` and run
- [ ] Create git tag: `git tag v0.4.0 && git push --tags`
- [ ] CI/CD publishes automatically

---

## User Installation Summary

### For Developers (Local Development)

```bash
# 1. Install VSCode extension
# → Search "FlowMason" in Extensions panel

# 2. Install Python runtime
pip install flowmason

# 3. Initialize project
fm init
fm studio start
```

### For Operations (Production/Staging)

```bash
# Pull and run Docker image
docker pull flowmason/studio:0.4.0

# Or use docker-compose
curl -O https://flowmason.com/docker-compose.yml
docker-compose up -d
```

---

## Pricing Model Considerations

With closed-source distribution, you can implement:

| Model | How |
|-------|-----|
| **Free** | Publish everything, no restrictions |
| **Freemium** | Free local, paid production features |
| **License Key** | Check key on startup, disable without valid key |
| **Usage-Based** | Track API calls, charge based on usage |
| **Enterprise** | Private Docker registry, custom contracts |

The distribution channels (Marketplace, PyPI, Docker Hub) all support both free and commercial software.


---

## 08-packaging-deployment/publishing-to-pypi.md

# Publishing FlowMason to PyPI

This guide covers how to publish FlowMason as a **closed-source/proprietary** package to the Python Package Index (PyPI).

## Overview

### Distribution Model

FlowMason is distributed as a **proprietary package** on PyPI:
- **Wheel only** - No source distribution (keeps code private)
- **Proprietary license** - Not open source
- **No public repository required** - Website URLs instead of GitHub

```
┌─────────────────────────────────────────────────────────────────┐
│                    CLOSED-SOURCE PyPI                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   Build                    Publish                   Install    │
│   ┌─────────────┐         ┌─────────────┐         ┌──────────┐ │
│   │ python -m   │         │   twine     │         │   pip    │ │
│   │ build       │────────►│   upload    │────────►│ install  │ │
│   │ --wheel     │         │   dist/*    │         │flowmason │ │
│   └─────────────┘         └─────────────┘         └──────────┘ │
│        │                                                        │
│        ▼                                                        │
│   .whl only (no .tar.gz)                                       │
│   = Compiled code, no source                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

### Package Structure

```
flowmason/
├── pyproject.toml           # Single package: "flowmason"
├── core/flowmason_core/     # Core framework
├── studio/flowmason_studio/ # Backend server
└── lab/flowmason_lab/       # Built-in components
```

### Publishing Options

| Option | Package Name | Install Command |
|--------|--------------|-----------------|
| **Single Package** | `flowmason` | `pip install flowmason` |
| **Split Packages** | `flowmason-core`, `flowmason-studio`, `flowmason-lab` | `pip install flowmason-core` |

This guide covers the **single package** approach. See [Splitting Packages](#splitting-into-multiple-packages) for the alternative.

---

## Prerequisites

### 1. Create PyPI Account

1. Go to [https://pypi.org/account/register/](https://pypi.org/account/register/)
2. Create an account and verify your email
3. Enable 2FA (required for publishing)

### 2. Create TestPyPI Account (Recommended)

1. Go to [https://test.pypi.org/account/register/](https://test.pypi.org/account/register/)
2. Create a separate account (TestPyPI is independent)
3. Use TestPyPI to test publishing before going to production

### 3. Generate API Tokens

**For PyPI:**
1. Go to [https://pypi.org/manage/account/token/](https://pypi.org/manage/account/token/)
2. Click "Add API token"
3. Name: `flowmason-publish`
4. Scope: "Entire account" (first time) or project-specific (after first publish)
5. Copy and save the token (starts with `pypi-`)

**For TestPyPI:**
1. Go to [https://test.pypi.org/manage/account/token/](https://test.pypi.org/manage/account/token/)
2. Same process, token starts with `pypi-`

### 4. Install Build Tools

```bash
pip install build twine
```

---

## Step-by-Step Publishing

### Step 1: Configure pyproject.toml for Closed-Source

Update `pyproject.toml` for proprietary distribution:

```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "flowmason"
version = "0.4.0"  # Update version before each release
description = "Universal AI Workflow Infrastructure"
readme = "README.md"
requires-python = ">=3.11"
license = "Proprietary"  # NOT open source
keywords = ["ai", "workflow", "llm", "pipeline", "automation"]
authors = [
    { name = "FlowMason", email = "support@flowmason.com" }
]
classifiers = [
    "Development Status :: 4 - Beta",
    "Intended Audience :: Developers",
    "License :: Other/Proprietary License",  # Proprietary classifier
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Topic :: Software Development :: Libraries :: Python Modules",
    "Topic :: Scientific/Engineering :: Artificial Intelligence",
]
dependencies = [
    "pydantic>=2.0.0",
    "fastapi>=0.109.0",
    "uvicorn[standard]>=0.27.0",
    "python-multipart>=0.0.6",
    "typer>=0.9.0",
    "rich>=13.0.0",
    "httpx>=0.26.0",
]

# Website URLs instead of GitHub (no public repo needed)
[project.urls]
Homepage = "https://flowmason.com"
Documentation = "https://flowmason.com/docs"
Support = "https://flowmason.com/support"

[project.scripts]
flowmason = "flowmason_core.cli.main:cli"
fm = "flowmason_core.cli.main:cli"

[tool.hatch.build.targets.wheel]
packages = ["core/flowmason_core", "studio/flowmason_studio", "lab/flowmason_lab"]
```

**Key differences for closed-source:**
- `license = "Proprietary"` - Indicates not open source
- `License :: Other/Proprietary License` - PyPI classifier
- URLs point to website, not GitHub
- No `Repository` or `Issues` URLs needed

### Step 2: Update Version

Before each release, update the version in `pyproject.toml`:

```toml
version = "0.4.0"  # Use semantic versioning
```

**Semantic Versioning:**
- `MAJOR.MINOR.PATCH`
- `0.4.0` → `0.4.1` (bug fix)
- `0.4.0` → `0.5.0` (new feature)
- `0.4.0` → `1.0.0` (breaking change / production ready)

### Step 3: Create README.md

Create `README.md` at repository root (becomes the PyPI project page):

```markdown
# FlowMason

Universal AI Workflow Infrastructure for building, debugging, and deploying intelligent pipelines.

## Installation

```bash
pip install flowmason
```

## Quick Start

```bash
# Initialize a project
fm init

# Start the Studio backend
fm studio start

# Run a pipeline
fm run pipelines/main.pipeline.json
```

## Documentation

Visit [https://flowmason.com/docs](https://flowmason.com/docs)

## Support

- Documentation: https://flowmason.com/docs
- Support: https://flowmason.com/support
- Email: support@flowmason.com

## License

Proprietary software. See LICENSE file for terms.
```

### Step 4: Create LICENSE File

Create a `LICENSE` file for proprietary distribution:

```
FlowMason Proprietary License

Copyright (c) 2025 FlowMason

All rights reserved.

This software and associated documentation files (the "Software") are proprietary
and confidential. Unauthorized copying, modification, distribution, or use of
this Software, via any medium, is strictly prohibited.

The Software is licensed, not sold. You may use this Software only in accordance
with the terms of your license agreement.

The Software is provided "as is", without warranty of any kind, express or implied,
including but not limited to the warranties of merchantability, fitness for a
particular purpose and noninfringement.

For licensing inquiries, contact: licensing@flowmason.com
```

### Step 5: Build the Package (Wheel Only)

**Important:** Build **wheel only** (no source distribution) to keep code private.

```bash
cd /path/to/flowmason

# Clean previous builds
rm -rf dist/ build/ *.egg-info

# Build WHEEL ONLY (not source distribution)
python -m build --wheel
```

This creates:
```
dist/
└── flowmason-1.0.0-py3-none-any.whl  # Wheel only (no .tar.gz)
```

**Note:** The `.tar.gz` source distribution would expose your source code. By building `--wheel` only, users get compiled bytecode.

### Step 6: Verify the Build

```bash
# Check the package contents
twine check dist/*

# List files in the wheel (verify no source exposed)
unzip -l dist/flowmason-1.0.0-py3-none-any.whl
```

### Step 7: Test with TestPyPI (Recommended)

**Upload to TestPyPI:**
```bash
twine upload --repository testpypi dist/*
```

You'll be prompted for credentials:
- Username: `__token__`
- Password: Your TestPyPI API token (including `pypi-` prefix)

**Test Installation:**
```bash
# Create a fresh virtual environment
python -m venv test-env
source test-env/bin/activate

# Install from TestPyPI
pip install --index-url https://test.pypi.org/simple/ \
    --extra-index-url https://pypi.org/simple/ \
    flowmason

# Verify it works
fm --version
```

### Step 8: Publish to PyPI

Once testing passes:

```bash
twine upload dist/*
```

Credentials:
- Username: `__token__`
- Password: Your PyPI API token

### Step 9: Verify on PyPI

1. Go to [https://pypi.org/project/flowmason/](https://pypi.org/project/flowmason/)
2. Verify the description, version, and metadata
3. Test installation:

```bash
pip install flowmason
fm --version
```

---

## Automating with GitHub Actions (Private Repo)

For a **private repository**, create `.github/workflows/publish.yml`:

```yaml
name: Publish to PyPI

on:
  release:
    types: [published]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install build tools
        run: pip install build twine

      - name: Build wheel only (no source distribution)
        run: python -m build --wheel

      - name: Check package
        run: twine check dist/*

      - name: Publish to PyPI
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: twine upload dist/*
```

**Key:** Uses `--wheel` to avoid exposing source code.

**Setup:**
1. Go to repository Settings → Secrets → Actions
2. Add secret `PYPI_API_TOKEN` with your PyPI token

**Usage:**
1. Create a GitHub Release
2. The workflow automatically publishes to PyPI

---

## Using Trusted Publishing (Alternative)

PyPI supports "Trusted Publishing" which eliminates the need for API tokens. However, this requires linking your GitHub repository to PyPI, which may not be ideal for private repos.

### Setup on PyPI

1. Go to [https://pypi.org/manage/account/publishing/](https://pypi.org/manage/account/publishing/)
2. Add a new publisher:
   - Owner: `your-github-username`
   - Repository: `flowmason` (can be private)
   - Workflow: `publish.yml`
   - Environment: `release` (optional)

### Updated GitHub Action

```yaml
name: Publish to PyPI

on:
  release:
    types: [published]

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      id-token: write  # Required for trusted publishing
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install build tools
        run: pip install build

      - name: Build wheel only
        run: python -m build --wheel

      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
```

No API token secrets needed - PyPI trusts the GitHub Actions identity.

**Note:** Even with trusted publishing from a private repo, only the wheel (compiled code) is published, not your source.

---

## Splitting into Multiple Packages

If you want separate packages (`flowmason-core`, `flowmason-studio`, `flowmason-lab`):

### 1. Create Individual pyproject.toml Files

**core/pyproject.toml:**
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "flowmason-core"
version = "0.4.0"
description = "FlowMason Core Framework"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
    "pydantic>=2.0.0",
    "typer>=0.9.0",
    "rich>=13.0.0",
    "httpx>=0.26.0",
]

[project.scripts]
flowmason = "flowmason_core.cli.main:cli"
fm = "flowmason_core.cli.main:cli"
```

**studio/pyproject.toml:**
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "flowmason-studio"
version = "0.4.0"
description = "FlowMason Studio Backend"
requires-python = ">=3.11"
dependencies = [
    "flowmason-core>=0.4.0",
    "fastapi>=0.109.0",
    "uvicorn[standard]>=0.27.0",
]
```

**lab/pyproject.toml:**
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "flowmason-lab"
version = "0.4.0"
description = "FlowMason Built-in Components"
requires-python = ">=3.11"
dependencies = [
    "flowmason-core>=0.4.0",
]
```

### 2. Publish Order

Publish in dependency order:
1. `flowmason-core` (no FlowMason dependencies)
2. `flowmason-studio` (depends on core)
3. `flowmason-lab` (depends on core)

### 3. GitHub Action for Multiple Packages

```yaml
name: Publish Packages

on:
  release:
    types: [published]

jobs:
  publish:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        package: [core, studio, lab]
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install build tools
        run: pip install build twine

      - name: Build wheel only
        working-directory: ${{ matrix.package }}
        run: python -m build --wheel

      - name: Publish to PyPI
        working-directory: ${{ matrix.package }}
        env:
          TWINE_USERNAME: __token__
          TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
        run: twine upload dist/*
```

---

## Version Management

### Manual Versioning

Update version in `pyproject.toml` before each release.

### Automatic Versioning with Git Tags

Use `hatch-vcs` for automatic versioning from git tags:

```toml
[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"

[project]
dynamic = ["version"]

[tool.hatch.version]
source = "vcs"
```

Then version comes from git tags:
```bash
git tag v0.4.0
git push --tags
```

---

## Checklist Before Publishing

- [ ] Version updated in `pyproject.toml`
- [ ] License set to `"Proprietary"`
- [ ] README.md is up to date (becomes PyPI page)
- [ ] LICENSE file exists with proprietary terms
- [ ] URLs point to website (not GitHub)
- [ ] All tests pass (`pytest`)
- [ ] Code is linted (`ruff check .`)
- [ ] Built with `--wheel` only (no source distribution)
- [ ] Tested on TestPyPI first
- [ ] Verified installation in fresh environment
- [ ] Verified no source files exposed in wheel

---

## Troubleshooting

### "Package already exists"

Each version can only be published once. Bump the version number.

### "Invalid distribution"

Run `twine check dist/*` to see what's wrong. Common issues:
- Missing README.md
- Invalid classifiers
- Malformed pyproject.toml

### "Authentication failed"

- Use `__token__` as username (literally)
- Use the full token including `pypi-` prefix
- Ensure 2FA is enabled on your PyPI account

### Package doesn't include all files

Check `[tool.hatch.build.targets.wheel]` in pyproject.toml:

```toml
[tool.hatch.build.targets.wheel]
packages = ["core/flowmason_core", "studio/flowmason_studio", "lab/flowmason_lab"]
```

---

## Closed-Source Summary

| Aspect | How to Keep Private |
|--------|---------------------|
| **Source Code** | Build `--wheel` only (no `.tar.gz`) |
| **License** | Use `"Proprietary"` license |
| **Repository** | Keep GitHub repo private |
| **URLs** | Point to website, not GitHub |
| **Distribution** | Users get compiled `.pyc` files in wheel |

**What users CAN see:**
- Package name, description, version on PyPI
- README content (your marketing page)
- List of dependencies
- Compiled Python bytecode (`.pyc` files)

**What users CANNOT see:**
- Original `.py` source files
- Internal implementation details
- Private repository

**Note:** Python bytecode can be decompiled, but it's not trivial. For additional protection, consider tools like PyArmor or Cython compilation.

---

## Links

- [PyPI](https://pypi.org/)
- [TestPyPI](https://test.pypi.org/)
- [Python Packaging Guide](https://packaging.python.org/)
- [Hatchling Documentation](https://hatch.pypa.io/)
- [Trusted Publishing](https://docs.pypi.org/trusted-publishers/)


---

## 09-debugging-testing/debugging/current-debugging.md

# Debugging Pipelines

FlowMason provides comprehensive debugging capabilities through VSCode's Debug Adapter Protocol (DAP).

## Quick Start

1. Open a `.pipeline.json` file
2. Set breakpoints (F9 on a stage in the JSON or DAG view)
3. Press F5 to start debugging
4. Step through with F10

## Debug Adapter Protocol (DAP)

FlowMason implements VSCode's standard Debug Adapter Protocol, providing:

- Breakpoints on pipeline stages
- Step over (next stage)
- Step into (sub-pipelines)
- Variables inspection
- Watch expressions
- Call stack view
- Exception breakpoints

## Setting Breakpoints

### In JSON Editor

Click in the gutter next to a stage definition:

```json
{
  "stages": [
    {
      "id": "fetch",        // ← Click gutter here
      "component_type": "http-request",
      ...
    }
  ]
}
```

### In DAG Canvas

Right-click a stage node > "Toggle Breakpoint"

Or click the breakpoint indicator on the node.

### Via Keyboard

1. Place cursor on stage
2. Press F9

### Conditional Breakpoints

Right-click breakpoint > "Edit Breakpoint":

```
Condition: {{fetch.output.status_code}} != 200
```

The breakpoint only triggers when the condition is true.

### Exception Breakpoints

Enable in the Breakpoints panel:
- Break on all exceptions
- Break on uncaught exceptions
- Break on specific error types (VALIDATION, TIMEOUT, etc.)

## Debug Controls

| Control | Keybinding | Description |
|---------|------------|-------------|
| Continue | F5 | Run to next breakpoint |
| Step Over | F10 | Execute next stage |
| Step Into | F11 | Enter sub-pipeline |
| Step Out | Shift+F11 | Exit sub-pipeline |
| Restart | Ctrl+Shift+F5 | Restart from beginning |
| Stop | Shift+F5 | Stop execution |

## Variables Panel

When paused, the Variables panel shows:

```
VARIABLES
├── Input
│   ├── url: "https://api.example.com"
│   └── method: "GET"
├── Output (after execution)
│   ├── body: {...}
│   └── status_code: 200
├── Context
│   ├── run_id: "run-abc123"
│   └── stage_id: "fetch"
└── Previous Stages
    └── setup
        └── output: {...}
```

### Inspecting Objects

Click to expand objects and arrays. Double-click to copy values.

## Watch Expressions

Add expressions to monitor:

```
{{fetch.output.body.data.length}}
{{process.output.items[0].name}}
{{context.run_id}}
```

## Call Stack

Shows the execution hierarchy:

```
CALL STACK
├── main-pipeline
│   ├── fetch (current) ●
│   ├── process
│   └── output
└── sub-pipeline (if entered)
    ├── step1
    └── step2
```

Click a frame to view its variables.

## Prompt Editor

During debugging of LLM stages, the Prompt Editor panel activates:

### Viewing Prompts

When paused at a @node stage:

```
┌─────────────────────────────────────────┐
│ PROMPT EDITOR                           │
├─────────────────────────────────────────┤
│ Stage: generate_content                 │
│ Component: generator                    │
├─────────────────────────────────────────┤
│ System Prompt:                          │
│ ┌─────────────────────────────────────┐ │
│ │ You are a helpful assistant...      │ │
│ └─────────────────────────────────────┘ │
│                                         │
│ User Prompt:                            │
│ ┌─────────────────────────────────────┐ │
│ │ Summarize the following text:       │ │
│ │ {{input.text}}                      │ │
│ └─────────────────────────────────────┘ │
│                                         │
│ [Edit] [Re-run] [Compare]               │
└─────────────────────────────────────────┘
```

### Editing Prompts

1. Click "Edit" to enable editing
2. Modify the prompt text
3. Click "Re-run Stage" to execute with new prompt
4. View output in the comparison panel

### Side-by-Side Comparison

Compare outputs from different prompt versions:

```
┌─────────────────┬─────────────────┐
│ Version 1       │ Version 2       │
├─────────────────┼─────────────────┤
│ Output:         │ Output:         │
│ The text talks  │ Key points:     │
│ about several   │ 1. Topic A      │
│ important...    │ 2. Topic B...   │
├─────────────────┼─────────────────┤
│ Tokens: 245     │ Tokens: 189     │
│ Time: 1.2s      │ Time: 0.9s      │
└─────────────────┴─────────────────┘
```

### Token Streaming

Watch LLM responses arrive in real-time:

```
Output (streaming):
The article discusses█
```

Enable in settings: `flowmason.debugger.showTokenStream`

## Debug Console

View execution logs and evaluate expressions:

```
> {{fetch.output.body}}
{ "data": [...], "meta": {...} }

> {{input.url.startsWith("https")}}
true
```

## Launch Configurations

Create `.vscode/launch.json`:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug Current Pipeline",
      "pipeline": "${file}",
      "stopOnEntry": true
    },
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug with Test Input",
      "pipeline": "pipelines/main.pipeline.json",
      "inputFile": "tests/input.json"
    },
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug Specific Stage",
      "pipeline": "pipelines/main.pipeline.json",
      "input": { "url": "https://example.com" },
      "breakpoints": ["process", "output"]
    }
  ]
}
```

### Configuration Options

| Property | Type | Description |
|----------|------|-------------|
| `pipeline` | string | Pipeline file path |
| `input` | object | Input data |
| `inputFile` | string | Path to JSON input file |
| `stopOnEntry` | boolean | Break on first stage |
| `breakOnException` | boolean | Break on any error |
| `breakpoints` | string[] | Pre-set breakpoint stage IDs |
| `env` | object | Environment variables |

## WebSocket Events

The debug session communicates via WebSocket:

```
ws://localhost:8999/api/v1/ws/runs
```

Events received during debugging:

| Event | Description |
|-------|-------------|
| `stage_started` | Stage began execution |
| `stage_completed` | Stage finished successfully |
| `stage_failed` | Stage encountered error |
| `execution_paused` | Hit breakpoint |
| `token_chunk` | LLM token received |
| `stream_start` | LLM streaming began |
| `stream_end` | LLM streaming ended |

## Debugging Control Flow

### Conditional Branches

When debugging a `conditional` stage:
1. Variables panel shows the condition value
2. Step over shows which branch was taken
3. Skipped branches are grayed in DAG

### Loops (ForEach)

When debugging a `foreach` stage:
1. Variables panel shows current item and index
2. Step through each iteration
3. Watch expression shows iteration progress

### Error Handling (TryCatch)

When debugging a `trycatch` stage:
1. Try stages execute normally
2. On error, catch stages execute
3. Exception breakpoints can pause on error
4. Variables show error details

## Troubleshooting

### Breakpoints Not Hit

- Ensure Studio is running
- Check breakpoint is on valid stage ID
- Verify pipeline path in launch config

### Variables Not Showing

- Wait for stage to complete
- Expand nested objects manually
- Check WebSocket connection

### Prompt Editor Empty

- Only available for @node components
- Stage must use LLM (context.llm)
- Wait for stage to pause (not complete)

### Debug Session Disconnects

- Check Studio server is running
- Check WebSocket connection
- Increase timeout in settings

## Best Practices

1. **Start Simple**: Debug one stage at a time
2. **Use Conditional Breakpoints**: Skip iterations in loops
3. **Watch Key Values**: Monitor important outputs
4. **Save Prompt Versions**: Keep successful prompt iterations
5. **Check Error Details**: Expand exception info in Variables

## See Also

- [VSCode Extension](../07-vscode-extension/overview.md)
- [Testing](./testing/pipeline-testing.md)
- [Control Flow](../03-concepts/control-flow.md)


---

## 09-debugging-testing/testing/pipeline-testing.md

# Testing Pipelines

FlowMason provides a comprehensive testing framework integrated with VSCode's Test Explorer.

## Quick Start

1. Create a `.test.json` file next to your pipeline
2. Define test cases with inputs and assertions
3. Run from Test Explorer or command line

## Test File Format

Create `pipelines/main.test.json`:

```json
{
  "name": "Main Pipeline Tests",
  "pipeline": "pipelines/main.pipeline.json",
  "tests": [
    {
      "name": "processes valid input",
      "input": {
        "url": "https://api.example.com/data"
      },
      "assertions": [
        { "path": "output.success", "equals": true },
        { "path": "output.data", "type": "array" }
      ]
    },
    {
      "name": "handles missing URL",
      "input": {},
      "expectError": "VALIDATION"
    }
  ]
}
```

## Test Structure

### Test File

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | string | Yes | Test suite name |
| `pipeline` | string | Yes | Path to pipeline file |
| `setup` | object | No | Setup before all tests |
| `teardown` | object | No | Cleanup after all tests |
| `tests` | array | Yes | Test cases |

### Test Case

| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `name` | string | Yes | Test case name |
| `input` | object | Yes | Pipeline input data |
| `assertions` | array | No* | Output assertions |
| `expectError` | string | No* | Expected error type |
| `timeout` | number | No | Test timeout (ms) |
| `skip` | boolean | No | Skip this test |

*Either `assertions` or `expectError` required.

## Assertions

### Equality

```json
{ "path": "output.status", "equals": "success" }
{ "path": "output.count", "equals": 42 }
{ "path": "output.enabled", "equals": true }
```

### Type Checks

```json
{ "path": "output.data", "type": "array" }
{ "path": "output.name", "type": "string" }
{ "path": "output.count", "type": "number" }
{ "path": "output.valid", "type": "boolean" }
{ "path": "output.config", "type": "object" }
```

### Comparisons

```json
{ "path": "output.score", "greaterThan": 0.5 }
{ "path": "output.score", "lessThan": 1.0 }
{ "path": "output.count", "greaterOrEqual": 10 }
{ "path": "output.count", "lessOrEqual": 100 }
```

### String Matching

```json
{ "path": "output.message", "contains": "success" }
{ "path": "output.email", "matches": "^[a-z]+@example\\.com$" }
{ "path": "output.url", "startsWith": "https://" }
{ "path": "output.filename", "endsWith": ".json" }
```

### Array Assertions

```json
{ "path": "output.items", "length": 5 }
{ "path": "output.items", "minLength": 1 }
{ "path": "output.items", "maxLength": 100 }
{ "path": "output.items", "contains": "apple" }
{ "path": "output.items", "notContains": "error" }
```

### Object Assertions

```json
{ "path": "output.data", "hasProperty": "id" }
{ "path": "output.data", "notHasProperty": "password" }
```

### Null/Undefined

```json
{ "path": "output.result", "exists": true }
{ "path": "output.error", "exists": false }
{ "path": "output.value", "notNull": true }
```

### Deep Equality

```json
{
  "path": "output.config",
  "deepEquals": {
    "enabled": true,
    "mode": "production",
    "features": ["a", "b"]
  }
}
```

### Custom Expressions

```json
{
  "path": "output",
  "expression": "data.length > 0 && data.every(item => item.valid)"
}
```

## Stage-Level Testing

Test specific stages, not just final output:

```json
{
  "tests": [
    {
      "name": "fetch stage returns data",
      "input": { "url": "https://api.example.com" },
      "stageAssertions": {
        "fetch": [
          { "path": "output.status_code", "equals": 200 }
        ],
        "transform": [
          { "path": "output.result", "type": "array" }
        ]
      }
    }
  ]
}
```

## Error Testing

### Expected Error Type

```json
{
  "name": "rejects invalid input",
  "input": { "url": "not-a-url" },
  "expectError": "VALIDATION"
}
```

Error types: `VALIDATION`, `COMPONENT`, `PROVIDER`, `TIMEOUT`, `CONNECTIVITY`, `CONFIGURATION`

### Expected Error Message

```json
{
  "name": "error message check",
  "input": {},
  "expectError": "VALIDATION",
  "errorContains": "url is required"
}
```

## Setup and Teardown

### Global Setup

```json
{
  "name": "API Tests",
  "pipeline": "pipelines/api.pipeline.json",
  "setup": {
    "variables": {
      "API_URL": "https://test.api.example.com",
      "AUTH_TOKEN": "test-token-123"
    }
  },
  "teardown": {
    "cleanup": ["temp_files"]
  },
  "tests": [...]
}
```

### Per-Test Setup

```json
{
  "tests": [
    {
      "name": "with custom setup",
      "setup": {
        "variables": { "MODE": "verbose" }
      },
      "input": { ... },
      "assertions": [...]
    }
  ]
}
```

## Running Tests

### From VSCode

1. Open Test Explorer (View > Testing)
2. Click Run button on test suite or individual test
3. View results inline

### From Command Line

```bash
# Run all tests
fm test

# Run specific test file
fm test pipelines/main.test.json

# Run tests matching pattern
fm test --filter "valid input"

# Run with coverage
fm test --coverage
```

### From API

```bash
curl -X POST http://localhost:8999/api/v1/tests/run \
  -H "Content-Type: application/json" \
  -d '{
    "test_file": "pipelines/main.test.json"
  }'
```

## Test Coverage

### Enable Coverage

```bash
fm test --coverage
```

### Coverage Report

```
Coverage Report
───────────────────────────────────────
Pipeline                    Coverage
───────────────────────────────────────
pipelines/main.pipeline.json    85%
  ├── fetch                     100%
  ├── transform                 100%
  ├── validate                  75%
  └── output                    66%
───────────────────────────────────────
Total                           85%
```

### Coverage in VSCode

- Gutters show covered/uncovered lines
- Test Explorer shows per-file coverage
- Coverage panel shows summary

## Mocking

### Mock HTTP Responses

```json
{
  "tests": [
    {
      "name": "handles API response",
      "mocks": {
        "http-request": {
          "output": {
            "status_code": 200,
            "body": { "data": [1, 2, 3] }
          }
        }
      },
      "input": { "url": "https://api.example.com" },
      "assertions": [...]
    }
  ]
}
```

### Mock LLM Responses

```json
{
  "tests": [
    {
      "name": "test prompt handling",
      "mocks": {
        "generator": {
          "output": {
            "content": "Mocked response text",
            "usage": { "input_tokens": 10, "output_tokens": 20 }
          }
        }
      },
      "input": { "topic": "test" },
      "assertions": [...]
    }
  ]
}
```

## Snapshot Testing

Compare output against saved snapshots:

```json
{
  "tests": [
    {
      "name": "output matches snapshot",
      "input": { "url": "https://api.example.com" },
      "snapshot": "tests/snapshots/api-response.json"
    }
  ]
}
```

### Update Snapshots

```bash
fm test --update-snapshots
```

## Best Practices

1. **Test the Happy Path**: Always test successful execution
2. **Test Error Cases**: Verify error handling works
3. **Use Mocks**: Mock external services for reliability
4. **Test Stages**: Don't just test final output
5. **Keep Tests Fast**: Use mocks for slow operations
6. **Descriptive Names**: Make test names explain the scenario
7. **Coverage Goals**: Aim for 80%+ coverage

## CI/CD Integration

### GitHub Actions

```yaml
- name: Run FlowMason Tests
  run: |
    fm test --coverage --reporter json > test-results.json

- name: Upload Coverage
  uses: codecov/codecov-action@v3
  with:
    files: ./coverage.json
```

### Test Results Format

```json
{
  "suite": "Main Pipeline Tests",
  "passed": 5,
  "failed": 1,
  "skipped": 0,
  "duration": 3450,
  "tests": [
    {
      "name": "processes valid input",
      "status": "passed",
      "duration": 1200
    },
    {
      "name": "handles edge case",
      "status": "failed",
      "error": "Expected 'success' but got 'error'",
      "duration": 450
    }
  ]
}
```

## See Also

- [Debugging](./debugging/current-debugging.md)
- [VSCode Extension](../07-vscode-extension/overview.md)
- [Pipelines](../03-concepts/pipelines.md)


---

## 10-architecture/core/execution-engine.md

# Execution Engine

## Overview

The FlowMason execution engine consists of two main executors:

1. **DAGExecutor** - Orchestrates pipeline execution with parallel wave-based processing
2. **UniversalExecutor** - Executes individual components with timeout and retry support

**Location:** `core/flowmason_core/execution/universal_executor.py`

## DAGExecutor

The DAGExecutor runs complete pipelines with support for:
- Wave-based parallel execution of independent stages
- Sequential execution mode (backwards compatible)
- Control flow handling (conditional, foreach, trycatch, router, return)
- Cancellation support via CancellationToken
- ExecutionHooks for debugging and monitoring

```python
class DAGExecutor:
    def __init__(
        self,
        registry: ComponentRegistry,
        context: ExecutionContext,
        providers: Optional[Dict[str, Any]] = None,
        default_provider: Optional[str] = None,
        hooks: Optional[ExecutionHooks] = None,
        max_concurrency: int = 10,      # Max parallel stages
        parallel_execution: bool = True  # Enable parallel mode
    ):
        self.executor = UniversalExecutor(registry, context)
        self.control_flow_handler = ControlFlowHandler(self)

    async def execute(
        self,
        stages: list,
        pipeline_input: Dict[str, Any],
        cancellation_token: Optional[CancellationToken] = None,
    ) -> Dict[str, ComponentResult]:
        # Parallel wave execution or sequential
        if self.parallel_execution:
            await self._execute_parallel(...)
        else:
            await self._execute_sequential(...)
```

### Wave-Based Parallel Execution

Independent stages execute concurrently in waves:

```
Input
  │
  ▼
Wave 1: [Stage A, Stage B]  ← Execute in parallel
              │
              ▼
Wave 2: [Stage C]  ← Depends on A and B
              │
              ▼
Wave 3: [Stage D, Stage E, Stage F]  ← All depend on C
```

Features:
- **Semaphore-controlled concurrency** - max_concurrency limits parallel tasks
- **Dependency-aware** - Stages wait for all dependencies
- **Control flow aware** - Respects skip_stages and early return

### Topological Sort

Uses Kahn's algorithm to order stages by dependencies:

```python
def _topological_sort(self, stages: list) -> list:
    stage_map = {s.id: s for s in stages}
    in_degree = {s.id: len(s.depends_on) for s in stages}

    ready = [s for s in stages if len(s.depends_on) == 0]
    sorted_stages = []

    while ready:
        stage = ready.pop(0)
        sorted_stages.append(stage)

        for other in stages:
            if stage.id in other.depends_on:
                in_degree[other.id] -= 1
                if in_degree[other.id] == 0:
                    ready.append(other)

    return sorted_stages
```

## UniversalExecutor

Executes ANY component type (node, operator, control_flow) uniformly.

Features:
- **Timeout enforcement** via `asyncio.wait_for()`
- **Retry logic** with exponential backoff
- **Error classification** (MuleSoft-inspired error types)
- **Tracing** with span attributes

```python
class UniversalExecutor:
    async def execute_component(
        self,
        component_config: ComponentConfig,
        upstream_outputs: Optional[Dict[str, Any]] = None
    ) -> ComponentResult:
        # 1. Load component from registry
        ComponentClass = self.registry.get_component_class(component_config.type)

        # 2. Get metadata (timeout, retry config)
        metadata = self.registry.get_component_metadata(component_config.type)

        # 3. Map config to Input model
        component_input = self.mapper.map_config_to_input(
            component_config,
            ComponentClass.Input,
            upstream_outputs
        )

        # 4. Determine timeout
        timeout_ms = self._get_timeout(component_config, metadata)

        # 5. Execute with timeout and retry
        result = await self._execute_with_timeout_and_retry(
            component_instance,
            component_input,
            context,
            component_config,
            timeout_ms
        )

        # 6. Validate output
        self._validate_output(result, ComponentClass)

        return ComponentResult(...)
```

### Timeout Enforcement

Timeouts are enforced at execution time:

```python
async def _execute_with_timeout_and_retry(self, ...):
    timeout_seconds = timeout_ms / 1000.0

    async def execute_once():
        try:
            return await asyncio.wait_for(
                component.execute(input, context),
                timeout=timeout_seconds,
            )
        except asyncio.TimeoutError:
            raise TimeoutExecutionError(
                component_id=component_config.id,
                timeout_ms=timeout_ms,
            )

    # Execute with retry if configured
    if retry_config and retry_config.max_retries > 0:
        return await with_retry(execute_once, retry_config, ...)
    else:
        return await execute_once()
```

**Timeout Priority:**
1. `ComponentConfig.timeout_ms` (explicit config)
2. `metadata.timeout_seconds` (from decorator)
3. Default: 60s for nodes, 30s for operators

### Retry Logic

Integrated retry with exponential backoff:

```python
# In retry.py
async def with_retry(
    func: Callable,
    config: RetryConfig,
    component_id: str,
    component_type: str,
    on_retry: Optional[Callable] = None,
) -> Any:
    for attempt in range(config.max_retries + 1):
        try:
            return await func()
        except Exception as e:
            if not is_retryable(e, config):
                raise

            if attempt == config.max_retries:
                raise RetryExhaustedError(...)

            delay = calculate_backoff(attempt, config)
            if on_retry:
                await on_retry(attempt, e, delay)
            await asyncio.sleep(delay / 1000)
```

### Input Mapping

Resolves template references like `{{fetch.output.body}}`:

```python
# In config/input_mapper.py
def map_config_to_input(self, config, InputClass, upstream_outputs):
    def resolve_template(value):
        if isinstance(value, str) and "{{" in value:
            # Handle input.* references
            if value.startswith("{{input."):
                return get_nested(pipeline_input, path)

            # Handle stage.* references
            stage_id, field_path = parse_template(value)
            return get_nested(upstream_outputs[stage_id], field_path)

        return value

    return InputClass(**{k: resolve_template(v) for k, v in config.items()})
```

## ControlFlowHandler

**Location:** `core/flowmason_core/execution/control_flow_handler.py`

Processes ControlFlowDirective from control flow components.

### Supported Control Flow Types

| Type | Description | Implementation |
|------|-------------|----------------|
| **CONDITIONAL** | If/else branching | Adds branches to `skip_stages` |
| **ROUTER** | Switch/case routing | Adds non-matching routes to `skip_stages` |
| **FOREACH** | Loop iteration | Executes loop_stages inline for each item |
| **TRYCATCH** | Error handling | Executes try/catch/finally inline |
| **SUBPIPELINE** | Nested pipeline | Calls subpipeline_executor callback |
| **RETURN** | Early exit | Sets `should_return` flag |

### TryCatch Handling

Executes try_stages, catches errors, runs catch_stages and finally_stages:

```python
async def _handle_trycatch(self, ...):
    # Skip all stages in main DAG (execute inline)
    for skip_id in try_stages + catch_stages + finally_stages:
        self.state.skip_stages.add(skip_id)

    # PHASE 1: Execute try_stages
    try:
        for stage in try_stages:
            result = await self.executor.execute_component(stage, upstream)
            all_results[stage.id] = result
    except Exception as e:
        caught_error = e

    # PHASE 2: Execute catch_stages (if error)
    if caught_error and catch_stages:
        for stage in catch_stages:
            result = await self.executor.execute_component(stage, upstream)
            # Error context available via upstream[trycatch_id].error

    # PHASE 3: Execute finally_stages (always)
    for stage in finally_stages:
        result = await self.executor.execute_component(stage, upstream)

    # PHASE 4: Propagate or continue based on error_scope
    if caught_error and error_scope == "propagate":
        raise caught_error  # MuleSoft on-error-propagate
    # else: continue (on-error-continue)
```

### ForEach Handling

Supports sequential and parallel iteration:

```python
async def _handle_foreach(self, ...):
    items = directive.loop_items
    loop_stages = metadata.get("loop_stages", [])
    parallel = metadata.get("parallel", False)
    max_parallel = metadata.get("max_parallel", 5)

    if parallel:
        # Parallel with semaphore
        semaphore = asyncio.Semaphore(max_parallel)
        tasks = [process_item(idx, item) for idx, item in enumerate(items)]
        results = await asyncio.gather(*tasks)
    else:
        # Sequential
        for idx, item in enumerate(items):
            await process_item(idx, item)
```

### ControlFlowState

Tracks execution state modifications:

```python
@dataclass
class ControlFlowState:
    skip_stages: Set[str] = field(default_factory=set)
    should_return: bool = False
    return_value: Any = None
    return_message: Optional[str] = None
    loop_contexts: Dict[str, LoopContext] = field(default_factory=dict)
    trycatch_contexts: Dict[str, TryCatchState] = field(default_factory=dict)
    subpipeline_results: Dict[str, Any] = field(default_factory=dict)
```

## ExecutionHooks

Protocol for observability and debug control:

```python
class ExecutionHooks(Protocol):
    async def check_and_wait_at_stage(
        self,
        stage_id: str,
        stage_name: Optional[str] = None,
    ) -> bool:
        """Called BEFORE executing each stage. Return False to stop."""
        ...

    async def on_stage_started(
        self,
        stage_id: str,
        component_type: str,
        stage_name: Optional[str] = None,
        input_data: Optional[Dict[str, Any]] = None,
    ) -> None:
        """Called when a stage starts execution."""
        ...

    async def on_stage_completed(
        self,
        stage_id: str,
        component_type: str,
        status: str,
        output: Any = None,
        duration_ms: Optional[int] = None,
        input_tokens: Optional[int] = None,
        output_tokens: Optional[int] = None,
    ) -> None:
        """Called when a stage completes successfully."""
        ...

    async def on_stage_failed(
        self,
        stage_id: str,
        component_type: str,
        error: str,
    ) -> None:
        """Called when a stage fails."""
        ...

    async def on_run_started(
        self,
        pipeline_id: str,
        stage_ids: List[str],
        inputs: Dict[str, Any],
    ) -> None:
        """Called when a run starts."""
        ...

    async def on_run_completed(
        self,
        pipeline_id: str,
        status: str,
        output: Any = None,
        total_duration_ms: Optional[int] = None,
    ) -> None:
        """Called when a run completes."""
        ...

    async def on_run_failed(
        self,
        pipeline_id: str,
        error: str,
        failed_stage_id: Optional[str] = None,
    ) -> None:
        """Called when a run fails."""
        ...
```

## Cancellation

Pass a CancellationToken to support graceful cancellation:

```python
# Create token
token = CancellationToken()

# Pass to executor
result = await dag_executor.execute(stages, input, cancellation_token=token)

# Cancel from another task
token.cancel("User requested stop")
```

The executor checks `token.is_cancelled` before each stage.

## Result Types

### ComponentResult

```python
@dataclass
class ComponentResult:
    component_id: str
    component_type: str
    status: str = "success"  # success, error, skipped
    error: Optional[str] = None
    output: Any = None
    usage: UsageMetrics = field(default_factory=UsageMetrics)
    trace_id: Optional[str] = None
    span_id: Optional[str] = None
    started_at: Optional[datetime] = None
    completed_at: Optional[datetime] = None
```

### UsageMetrics

```python
@dataclass
class UsageMetrics:
    input_tokens: int = 0
    output_tokens: int = 0
    total_tokens: int = 0
    cost_usd: float = 0.0
    duration_ms: int = 0
    provider: Optional[str] = None
    model: Optional[str] = None

    def __add__(self, other: "UsageMetrics") -> "UsageMetrics":
        """Supports aggregation across stages."""
        return UsageMetrics(
            input_tokens=self.input_tokens + other.input_tokens,
            output_tokens=self.output_tokens + other.output_tokens,
            total_tokens=self.total_tokens + other.total_tokens,
            cost_usd=self.cost_usd + other.cost_usd,
            duration_ms=self.duration_ms + other.duration_ms
        )
```

## Error Types (MuleSoft-Inspired)

```python
class ErrorType(Enum):
    """Classification of errors for routing and handling."""
    CONNECTIVITY = "CONNECTIVITY"      # Network/connection issues
    TIMEOUT = "TIMEOUT"                # Operation timed out
    VALIDATION = "VALIDATION"          # Input/output validation
    TRANSFORMATION = "TRANSFORMATION"  # Data transformation failed
    EXPRESSION = "EXPRESSION"          # Expression evaluation failed
    ROUTING = "ROUTING"                # Pipeline routing issue
    SECURITY = "SECURITY"              # Auth/permission issues
    EXECUTION = "EXECUTION"            # General execution error
    RETRY_EXHAUSTED = "RETRY_EXHAUSTED"
    CANCELLATION = "CANCELLATION"
    UNKNOWN = "UNKNOWN"
```

## Future Improvements

1. **Streaming** - Stream LLM responses to client
2. **Checkpointing** - Save execution state for resume
3. **Distributed execution** - Execute stages across workers


---

## 10-architecture/system-overview.md

# System Architecture Overview

## High-Level Architecture

```
┌─────────────────────────────────────────────────────────────────────┐
│                         User Interface Layer                        │
├─────────────────────────────┬───────────────────────────────────────┤
│     VSCode Extension        │         Studio Frontend               │
│  ┌───────────────────────┐  │  ┌─────────────────────────────────┐  │
│  │ - IntelliSense        │  │  │ - Pipeline Builder (React)      │  │
│  │ - Diagnostics         │  │  │ - Component Palette             │  │
│  │ - CodeLens            │  │  │ - Debug Panel                   │  │
│  │ - Preview Webview     │  │  │ - Execution Timeline            │  │
│  │ - Studio Management   │  │  │ - Stage Configuration           │  │
│  └───────────────────────┘  │  └─────────────────────────────────┘  │
└─────────────────────────────┴───────────────────────────────────────┘
                                       │
                              HTTP/WebSocket
                                       │
┌──────────────────────────────────────▼──────────────────────────────┐
│                         API Layer (FastAPI)                         │
├─────────────────────────────────────────────────────────────────────┤
│  Routes:                                                            │
│  ├── /api/v1/registry     - Component management                    │
│  ├── /api/v1/pipelines    - Pipeline CRUD                           │
│  ├── /api/v1/runs         - Execution management                    │
│  ├── /api/v1/providers    - LLM provider config                     │
│  ├── /api/v1/settings     - App settings                            │
│  ├── /api/v1/logs         - Logging                                 │
│  └── /api/v1/ws/runs      - WebSocket for real-time updates         │
├─────────────────────────────────────────────────────────────────────┤
│  Services:                                                          │
│  ├── ExecutionController  - Debug commands (pause/resume/step)      │
│  ├── PipelineStorage      - Pipeline persistence                    │
│  └── RunStorage           - Execution history                       │
└─────────────────────────────────────────────────────────────────────┘
                                       │
┌──────────────────────────────────────▼──────────────────────────────┐
│                        Core Framework Layer                         │
├─────────────────────────────────────────────────────────────────────┤
│  Execution:                                                         │
│  ├── DAGExecutor          - Pipeline execution (topological sort)   │
│  ├── UniversalExecutor    - Component execution                     │
│  ├── ControlFlowHandler   - Process directives                      │
│  ├── ExecutionHooks       - Callbacks for observability             │
│  └── ExecutionTracer      - Span tracking                           │
├─────────────────────────────────────────────────────────────────────┤
│  Types:                                                             │
│  ├── NodeInput/Output     - Node type bases                         │
│  ├── OperatorInput/Output - Operator type bases                     │
│  ├── ControlFlowDirective - Flow control instructions               │
│  ├── FlowMasonError       - Error hierarchy                         │
│  └── UsageMetrics         - Token/cost tracking                     │
├─────────────────────────────────────────────────────────────────────┤
│  Registry:                                                          │
│  ├── ComponentRegistry    - Component discovery                     │
│  ├── MetadataExtractor    - Schema extraction                       │
│  └── PackageLoader        - .fmpkg loading                          │
└─────────────────────────────────────────────────────────────────────┘
                                       │
┌──────────────────────────────────────▼──────────────────────────────┐
│                         Component Layer                             │
├─────────────────────────────────────────────────────────────────────┤
│  Control Flow (6):        Operators (7):         Nodes (5):         │
│  ├── Conditional          ├── HttpRequest        ├── Generator      │
│  ├── ForEach              ├── JsonTransform      ├── Critic         │
│  ├── TryCatch             ├── Filter             ├── Improver       │
│  ├── Router               ├── SchemaValidate     ├── Selector       │
│  ├── SubPipeline          ├── VariableSet        └── Synthesizer    │
│  └── Return               └── Logger                                │
└─────────────────────────────────────────────────────────────────────┘
                                       │
┌──────────────────────────────────────▼──────────────────────────────┐
│                       External Services                             │
├─────────────────────────────────────────────────────────────────────┤
│  LLM Providers:           Storage:              External APIs:      │
│  ├── Anthropic            ├── SQLite            ├── HTTP endpoints  │
│  ├── OpenAI               └── File system       └── Webhooks        │
│  ├── Google                                                         │
│  └── Groq                                                           │
└─────────────────────────────────────────────────────────────────────┘
```

## Directory Structure

```
flowmason/
├── core/                           # Core framework
│   └── flowmason_core/
│       ├── core/                   # Decorators, types
│       │   ├── decorators.py       # @node, @operator, @control_flow
│       │   └── types.py            # NodeInput, NodeOutput, etc.
│       ├── execution/              # Execution engine
│       │   ├── universal_executor.py
│       │   ├── dag_executor.py
│       │   ├── control_flow_handler.py
│       │   ├── types.py            # FlowMasonError, UsageMetrics
│       │   ├── retry.py            # Retry logic (not integrated)
│       │   └── cancellation.py     # Cancellation (not integrated)
│       └── registry/               # Component discovery
│           ├── extractor.py
│           └── types.py
│
├── studio/                         # Studio application
│   └── flowmason_studio/
│       ├── api/                    # FastAPI backend
│       │   ├── app.py
│       │   ├── routes/
│       │   │   ├── registry.py
│       │   │   ├── pipelines.py
│       │   │   └── execution.py
│       │   └── websocket.py
│       ├── services/
│       │   └── execution_controller.py
│       └── models/
│           └── api.py
│   └── frontend/                   # React frontend
│       └── src/
│           ├── pages/
│           │   └── PipelineBuilder.tsx
│           ├── components/
│           │   ├── PipelineCanvas.tsx
│           │   └── debug/
│           └── services/
│               ├── api.ts
│               └── websocket.ts
│
├── lab/                            # Built-in components
│   └── flowmason_lab/
│       ├── nodes/
│       │   └── core/               # Generator, Critic, etc.
│       └── operators/
│           ├── core/               # HttpRequest, JsonTransform, etc.
│           └── control_flow/       # Conditional, ForEach, etc.
│
├── vscode-extension/               # VSCode extension
│   └── src/
│       ├── extension.ts
│       ├── commands/
│       ├── providers/
│       └── services/
│
└── fmdocs/                         # Documentation
```

## Key Components

### 1. Decorators

Three decorators mark classes as FlowMason components:

```python
# Node - AI-powered, requires LLM
@node(name="generator", ...)
class GeneratorNode: ...

# Operator - Deterministic, no LLM
@operator(name="http-request", ...)
class HttpRequestOperator: ...

# Control Flow - Modifies execution
@control_flow(name="conditional", control_flow_type="conditional", ...)
class ConditionalComponent: ...
```

### 2. Execution Engine

**DAGExecutor** - Orchestrates pipeline execution:
- Topological sort of stages
- Dependency resolution
- Sequential execution (parallel planned)

**UniversalExecutor** - Executes individual components:
- Input mapping and validation
- Component instantiation
- Output validation
- Tracing

### 3. WebSocket Real-Time

Events flow from executor → API → WebSocket → clients:

```
DAGExecutor.execute()
    │
    ├── hooks.on_stage_started(stage_id)
    │       │
    │       └── ExecutionController.on_stage_started()
    │               │
    │               └── WebSocket.broadcast("STAGE_STARTED")
    │                       │
    │                       └── Frontend receives event
    │
    └── hooks.on_stage_completed(stage_id, result)
```

### 4. Registry System

Components are discovered via:
1. Package scan (`~/.flowmason/packages/`)
2. Metadata extraction from decorated classes
3. Schema generation from Input/Output classes

## Data Models

### Pipeline

```python
class PipelineDetail(BaseModel):
    id: str
    name: str
    description: str
    version: str
    status: PipelineStatus  # DRAFT, PUBLISHED
    stages: List[PipelineStage]
    input_schema: Dict
    output_schema: Dict
```

### Stage

```python
class PipelineStage(BaseModel):
    id: str
    component: str
    depends_on: List[str] = []
    config: Dict[str, Any]
    llm_settings: Optional[LLMSettings]
```

### Component

```python
class ComponentInfo(BaseModel):
    component_type: str
    component_kind: str  # node, operator, control_flow
    category: str
    description: str
    input_schema: Dict
    output_schema: Dict
    requires_llm: bool
    timeout_seconds: int
```

## Current Limitations

| Area | Limitation | Status |
|------|------------|--------|
| Execution | Sequential only | Parallel planned |
| Timeout | Not enforced | Defined, not wired |
| Retry | Not integrated | Logic exists |
| Cancellation | Not integrated | Token exists |
| Storage | SQLite database | File-based planned |
| VSCode | Opens browser | Custom editor planned |


---

## tutorials/01-getting-started.md

# Tutorial 1: Getting Started with FlowMason

**Duration:** 15 minutes

In this tutorial, you'll install FlowMason and create your first project using VSCode.

## Prerequisites

- **Python** 3.11 or higher
- **Visual Studio Code** 1.85.0 or later
- Basic familiarity with Python

## Step 1: Install FlowMason CLI

Open a terminal and install FlowMason from PyPI:

```bash
pip install flowmason
```

Verify the installation:

```bash
fm --version
# Should show: FlowMason CLI v0.4.1
```

> **Tip:** If `fm` command is not found, see [Troubleshooting](#troubleshooting) at the end.

## Step 2: Install the VSCode Extension

### Option A: From VS Code Marketplace (Recommended)

1. Open VSCode
2. Go to **Extensions** (`Ctrl+Shift+X` / `Cmd+Shift+X`)
3. Search for "**FlowMason**"
4. Click **Install**

### Option B: From VSIX File

```bash
code --install-extension flowmason-0.10.0.vsix
```

After installation, you'll see:
- **FlowMason icon** in the Activity Bar (left sidebar)
- **FlowMason status** in the status bar at the bottom

## Step 3: Create a New Project

Use the VSCode Command Palette to create a new project:

1. Press `Ctrl+Shift+P` (Windows/Linux) or `Cmd+Shift+P` (Mac)
2. Type "**FlowMason: New Project**"
3. Press Enter

Follow the prompts:

| Prompt | Example Input |
|--------|---------------|
| Project name | `my-first-pipeline` |
| Description | `My first FlowMason project` |
| Author | `Your Name` |
| Include examples? | `Yes` |
| Location | Select a parent folder |

Click "**Open Project**" when prompted.

## Step 4: Explore the Project Structure

Your new project has this structure:

```
my-first-pipeline/
├── components/
│   ├── __init__.py
│   ├── example_node.py       # AI-powered component
│   └── example_operator.py   # Deterministic component
├── pipelines/
│   └── main.pipeline.json    # Your first pipeline
├── flowmason.json            # Project manifest
├── requirements.txt          # Dependencies
├── .gitignore
└── README.md
```

### Key Files

**`flowmason.json`** - Project configuration:
```json
{
  "name": "my-first-pipeline",
  "version": "1.0.0",
  "main": "pipelines/main.pipeline.json",
  "components": {
    "include": ["components/**/*.py"]
  },
  "providers": {
    "default": "anthropic",
    "anthropic": {
      "model": "claude-sonnet-4-20250514"
    }
  }
}
```

**`components/example_node.py`** - An AI node:
```python
@node(name="my-first-pipeline-processor", category="custom")
class MyFirstPipelineNode:
    class Input(NodeInput):
        text: str

    class Output(NodeOutput):
        result: str

    async def execute(self, input: Input, context) -> Output:
        # Uses LLM to process text
        ...
```

**`pipelines/main.pipeline.json`** - Your pipeline definition (open to see visual editor)

## Step 5: Start FlowMason Studio

Studio is the backend that executes pipelines.

### Using VSCode (Recommended)

1. Press `Ctrl+Shift+P` / `Cmd+Shift+P`
2. Type "**FlowMason: Start Studio**"
3. Press Enter

You'll see a notification: "FlowMason Studio started on port 8999"

The status bar will show: **FlowMason: Connected** ✓

### Using CLI

```bash
fm studio start
```

Check status:
```bash
fm studio status
```

## Step 6: Open the Visual Pipeline Editor

1. Click on `pipelines/main.pipeline.json` in the Explorer
2. The file opens in the JSON editor
3. Click "**Open DAG View**" in the editor toolbar (or `Ctrl+Shift+P` → "FlowMason: Open DAG View")

You'll see a visual representation of your pipeline stages.

## Step 7: Run Your First Pipeline

### Using VSCode (Recommended)

1. With `main.pipeline.json` open
2. Press `F5` to run the pipeline
3. Enter input when prompted:
   ```json
   {"text": "Hello, FlowMason!"}
   ```
4. View output in the Debug Console

### Using CLI

```bash
fm run pipelines/main.pipeline.json --input '{"text": "Hello, FlowMason!"}'
```

## Step 8: Explore VSCode Features

### FlowMason Panel (Activity Bar)

Click the FlowMason icon in the Activity Bar to see:

```
FLOWMASON
├── COMPONENTS
│   ├── Nodes
│   │   ├── generator
│   │   ├── critic
│   │   └── my-first-pipeline-processor
│   ├── Operators
│   │   ├── http-request
│   │   ├── json-transform
│   │   └── ...
│   └── Control Flow
│       ├── conditional
│       ├── foreach
│       └── ...
├── PIPELINES
│   └── main.pipeline.json
└── RUNS
    └── (execution history)
```

### Code Intelligence

Open `components/example_node.py` and notice:
- **Syntax highlighting** for decorators
- **Hover documentation** - Hover over `@node` to see docs
- **IntelliSense** - Autocomplete for imports and decorators
- **CodeLens** - "Run" and "Preview" buttons above components

### Keyboard Shortcuts

| Action | Shortcut |
|--------|----------|
| Run Pipeline | `F5` |
| Set Breakpoint | `F9` |
| Step Over | `F10` |
| Command Palette | `Ctrl+Shift+P` / `Cmd+Shift+P` |

## Step 9: Configure LLM Provider (Optional)

For AI nodes to call real LLMs, set your API key:

```bash
export ANTHROPIC_API_KEY=your-api-key-here
```

Or add to your shell profile (`~/.bashrc`, `~/.zshrc`).

## Step 10: Stop Studio

When done:

1. Press `Ctrl+Shift+P` / `Cmd+Shift+P`
2. Type "**FlowMason: Stop Studio**"

Or via CLI:
```bash
fm studio stop
```

## What You've Learned

- ✅ Installed FlowMason CLI (`pip install flowmason`)
- ✅ Installed VSCode extension
- ✅ Created a project using "FlowMason: New Project"
- ✅ Started FlowMason Studio
- ✅ Ran your first pipeline
- ✅ Explored the visual pipeline editor

## VSCode Commands Reference

| Command | Description |
|---------|-------------|
| FlowMason: New Project | Create a new project with structure |
| FlowMason: Start Studio | Start the backend server |
| FlowMason: Stop Studio | Stop the backend server |
| FlowMason: New Node | Create a new AI node |
| FlowMason: New Operator | Create a new operator |
| FlowMason: Open DAG View | Open visual pipeline editor |
| FlowMason: Refresh Registry | Refresh component list |

## Next Steps

Continue to [Tutorial 2: Building Your First Pipeline](02-building-first-pipeline.md) to create a multi-stage AI pipeline.

---

## Troubleshooting

### "fm: command not found"

Your Python scripts directory isn't in PATH:

```bash
# Option 1: Find and add to PATH
export PATH="$PATH:$(python -m site --user-base)/bin"

# Option 2: Use virtual environment
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate
pip install flowmason
fm --version
```

### Studio fails to start

Check if port 8999 is in use:
```bash
lsof -i :8999
# Kill the process or use different port:
fm studio start --port 9000
```

### Extension not showing

1. Reload VSCode: `Ctrl+Shift+P` → "Developer: Reload Window"
2. Check extension is enabled in Extensions panel
3. Ensure you have a folder open (not just a file)

### No components in sidebar

1. Ensure Studio is running (check status bar)
2. `Ctrl+Shift+P` → "FlowMason: Refresh Registry"
3. Check Output panel: View → Output → FlowMason


---

## tutorials/02-building-first-pipeline.md

# Tutorial 2: Building Your First Pipeline

This tutorial guides you through creating a complete AI pipeline that fetches content from a URL and generates a summary.

## What We'll Build

A 3-stage pipeline:
1. **fetch** - Retrieve content from a URL
2. **extract** - Extract the main text content
3. **summarize** - Generate an AI summary

```
[fetch] ──► [extract] ──► [summarize]
```

## Prerequisites

- Completed [Tutorial 1: Getting Started](./01-getting-started.md)
- Studio running (`fm studio start`)
- API key configured for your LLM provider

## Step 1: Create the Pipeline File

### Option A: Using Command Palette

1. Press `Cmd+Shift+P`
2. Type "FlowMason: New Pipeline"
3. Enter name: `content-summarizer`
4. A new file opens: `pipelines/content-summarizer.pipeline.json`

### Option B: Manual Creation

Create `pipelines/content-summarizer.pipeline.json`:

```json
{
  "$schema": "../.flowmason/schemas/pipeline.schema.json",
  "name": "content-summarizer",
  "version": "1.0.0",
  "description": "Fetches content from a URL and generates a summary",
  "input_schema": {
    "type": "object",
    "properties": {
      "url": {
        "type": "string",
        "description": "URL to fetch and summarize"
      },
      "max_length": {
        "type": "integer",
        "default": 200,
        "description": "Maximum summary length in words"
      }
    },
    "required": ["url"]
  },
  "stages": []
}
```

## Step 2: Add the Fetch Stage

The first stage fetches content from the provided URL.

### Using the Visual Editor

1. Click "Open DAG View" button in the editor toolbar
2. Click "Add Stage" or press `Cmd+Shift+A`
3. Select "Operators" → "http-request"
4. Enter stage ID: `fetch`

### JSON Configuration

Add to the `stages` array:

```json
{
  "id": "fetch",
  "component_type": "http-request",
  "description": "Fetch content from URL",
  "config": {
    "url": "{{input.url}}",
    "method": "GET",
    "timeout": 30
  }
}
```

### Understanding Template Syntax

- `{{input.url}}` - References the pipeline input
- `{{input.max_length}}` - Would reference max_length input
- Template expressions are evaluated at runtime

## Step 3: Add the Extract Stage

This stage extracts clean text from the HTML response.

Add to `stages`:

```json
{
  "id": "extract",
  "component_type": "json-transform",
  "description": "Extract text content",
  "depends_on": ["fetch"],
  "config": {
    "data": "{{fetch.output.body}}",
    "expression": "content || text || body"
  }
}
```

### Key Concepts

- `depends_on: ["fetch"]` - This stage runs after `fetch` completes
- `{{fetch.output.body}}` - References the output of the `fetch` stage
- The JMESPath expression extracts text content

## Step 4: Add the Summarize Stage

This AI stage generates the summary using an LLM.

Add to `stages`:

```json
{
  "id": "summarize",
  "component_type": "generator",
  "description": "Generate AI summary",
  "depends_on": ["extract"],
  "config": {
    "system_prompt": "You are a concise summarizer. Extract key points and present them clearly.",
    "prompt": "Summarize the following content in {{input.max_length}} words or less:\n\n{{extract.output.result}}",
    "temperature": 0.3,
    "max_tokens": 500
  }
}
```

### AI Node Configuration

| Field | Description |
|-------|-------------|
| `system_prompt` | Sets the AI's behavior/persona |
| `prompt` | The user message with template variables |
| `temperature` | Creativity level (0.0-2.0, lower = more focused) |
| `max_tokens` | Maximum response length |

## Step 5: Complete Pipeline

Your complete `content-summarizer.pipeline.json`:

```json
{
  "$schema": "../.flowmason/schemas/pipeline.schema.json",
  "name": "content-summarizer",
  "version": "1.0.0",
  "description": "Fetches content from a URL and generates a summary",
  "input_schema": {
    "type": "object",
    "properties": {
      "url": {
        "type": "string",
        "description": "URL to fetch and summarize"
      },
      "max_length": {
        "type": "integer",
        "default": 200,
        "description": "Maximum summary length in words"
      }
    },
    "required": ["url"]
  },
  "stages": [
    {
      "id": "fetch",
      "component_type": "http-request",
      "description": "Fetch content from URL",
      "config": {
        "url": "{{input.url}}",
        "method": "GET",
        "timeout": 30
      }
    },
    {
      "id": "extract",
      "component_type": "json-transform",
      "description": "Extract text content",
      "depends_on": ["fetch"],
      "config": {
        "data": "{{fetch.output.body}}",
        "expression": "content || text || body"
      }
    },
    {
      "id": "summarize",
      "component_type": "generator",
      "description": "Generate AI summary",
      "depends_on": ["extract"],
      "config": {
        "system_prompt": "You are a concise summarizer. Extract key points and present them clearly.",
        "prompt": "Summarize the following content in {{input.max_length}} words or less:\n\n{{extract.output.result}}",
        "temperature": 0.3,
        "max_tokens": 500
      }
    }
  ],
  "output": {
    "summary": "{{summarize.output.content}}",
    "source_url": "{{input.url}}"
  }
}
```

## Step 6: Validate the Pipeline

### Automatic Validation

The extension validates in real-time. Check the Problems panel (`Cmd+Shift+M`) for errors:

- Missing dependencies
- Unknown component types
- Invalid configuration
- Circular dependencies

### Manual Validation

```bash
fm validate pipelines/content-summarizer.pipeline.json
```

## Step 7: Run the Pipeline

### From VSCode

1. Open the pipeline file
2. Click the "Run" CodeLens above the pipeline name
3. Enter input when prompted:
   ```json
   {
     "url": "https://example.com/article",
     "max_length": 150
   }
   ```
4. View results in the Output panel

### From Command Line

```bash
fm run pipelines/content-summarizer.pipeline.json \
  --input '{"url": "https://example.com/article", "max_length": 150}'
```

### From API

```bash
curl -X POST http://localhost:8999/api/v1/runs \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline": "content-summarizer",
    "input": {
      "url": "https://example.com/article",
      "max_length": 150
    }
  }'
```

## Step 8: View the DAG Visualization

1. Open the pipeline file
2. Click "Open DAG View" in the toolbar
3. See your pipeline as a visual graph:

```
┌─────────┐     ┌─────────┐     ┌───────────┐
│  fetch  │────►│ extract │────►│ summarize │
└─────────┘     └─────────┘     └───────────┘
```

### DAG Interactions

- **Click** a stage to select it
- **Double-click** to edit configuration
- **Right-click** for context menu
- **Drag** to reposition nodes

## Adding Error Handling

Wrap risky operations with TryCatch:

```json
{
  "id": "safe_fetch",
  "component_type": "trycatch",
  "config": {
    "try_stages": ["fetch", "extract"],
    "catch_stages": ["handle_error"],
    "on_error": "continue"
  }
}
```

Add an error handler:

```json
{
  "id": "handle_error",
  "component_type": "logger",
  "config": {
    "level": "error",
    "message": "Failed to fetch: {{_error.message}}"
  }
}
```

## Adding Conditional Logic

Process different content types differently:

```json
{
  "id": "route_content",
  "component_type": "router",
  "depends_on": ["fetch"],
  "config": {
    "value": "{{fetch.output.content_type}}",
    "routes": {
      "text/html": "extract_html",
      "application/json": "extract_json",
      "text/plain": "extract_text"
    },
    "default": "extract_text"
  }
}
```

## Exercise: Extend the Pipeline

Try adding these features:

1. **Language Detection** - Add a stage to detect the content language
2. **Translation** - If not English, translate before summarizing
3. **Keywords** - Extract keywords from the summary
4. **Output Formatting** - Format the final output as Markdown

## Common Patterns

### Sequential Processing

```
[A] ──► [B] ──► [C]
```

```json
{ "id": "A" },
{ "id": "B", "depends_on": ["A"] },
{ "id": "C", "depends_on": ["B"] }
```

### Parallel Processing

```
      ┌──► [B] ──┐
[A] ──┤          ├──► [D]
      └──► [C] ──┘
```

```json
{ "id": "A" },
{ "id": "B", "depends_on": ["A"] },
{ "id": "C", "depends_on": ["A"] },
{ "id": "D", "depends_on": ["B", "C"] }
```

### Conditional Branching

```
        ┌──► [B] (if true)
[A] ──► │
        └──► [C] (if false)
```

```json
{
  "id": "branch",
  "component_type": "conditional",
  "depends_on": ["A"],
  "config": {
    "condition": "{{A.output.valid}}",
    "true_branch": "B",
    "false_branch": "C"
  }
}
```

## Next Steps

- [Tutorial 3: Debugging Pipelines](./03-debugging-pipelines.md) - Learn to debug with breakpoints
- [Tutorial 4: Testing Pipelines](./04-testing-pipelines.md) - Write tests for your pipeline
- [Tutorial 5: Working with Components](./05-working-with-components.md) - Create custom nodes


---

## tutorials/03-debugging-pipelines.md

# Tutorial 3: Debugging Pipelines

This tutorial teaches you how to debug FlowMason pipelines using VSCode's native debugging features.

## What You'll Learn

- Setting breakpoints on stages
- Stepping through execution
- Inspecting variables and outputs
- Editing prompts during debug
- Using the debug console

## Prerequisites

- Completed [Tutorial 2: Building Your First Pipeline](./02-building-first-pipeline.md)
- A working pipeline to debug
- Studio running

## Understanding Debug Adapter Protocol (DAP)

FlowMason implements VSCode's Debug Adapter Protocol, giving you:

- **Breakpoints** - Pause at specific stages
- **Step controls** - Step over, step into, continue
- **Variable inspection** - See inputs, outputs, context
- **Call stack** - Navigate pipeline hierarchy
- **Debug console** - Evaluate expressions

## Step 1: Create a Debug Configuration

Create `.vscode/launch.json` in your project:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug Current Pipeline",
      "pipeline": "${file}",
      "stopOnEntry": true
    },
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug Content Summarizer",
      "pipeline": "pipelines/content-summarizer.pipeline.json",
      "input": {
        "url": "https://example.com/article",
        "max_length": 150
      },
      "stopOnEntry": false,
      "breakOnException": true
    }
  ]
}
```

### Configuration Options

| Option | Type | Description |
|--------|------|-------------|
| `pipeline` | string | Path to pipeline file |
| `input` | object | Input data for the pipeline |
| `inputFile` | string | Path to JSON file with input |
| `stopOnEntry` | boolean | Break on first stage |
| `breakOnException` | boolean | Break on any error |
| `breakpoints` | string[] | Pre-set breakpoint stage IDs |

## Step 2: Set Breakpoints

### Method 1: Click the Gutter

1. Open your pipeline file
2. Find a stage definition
3. Click in the gutter (left margin) next to the stage ID
4. A red dot appears indicating the breakpoint

```json
{
  "stages": [
    {
      "id": "fetch",        // ← Click gutter here
      "component_type": "http-request",
      ...
    }
  ]
}
```

### Method 2: Keyboard Shortcut

1. Place cursor on a stage
2. Press `F9` to toggle breakpoint

### Method 3: DAG Canvas

1. Open the DAG view
2. Right-click a stage node
3. Select "Toggle Breakpoint"

### Method 4: Via Debug Configuration

```json
{
  "type": "flowmason",
  "name": "Debug with Breakpoints",
  "pipeline": "pipelines/main.pipeline.json",
  "breakpoints": ["extract", "summarize"]
}
```

## Step 3: Start Debugging

### Option A: Press F5

1. Open the pipeline file
2. Press `F5`
3. Select the debug configuration if prompted

### Option B: Debug Panel

1. Click the Run and Debug icon in the Activity Bar
2. Select your configuration from the dropdown
3. Click the green play button

### Option C: CodeLens

1. Open the pipeline file
2. Click "Debug" CodeLens above the pipeline name

## Step 4: Debug Controls

When paused at a breakpoint:

| Control | Keybinding | Description |
|---------|------------|-------------|
| Continue | `F5` | Run to next breakpoint |
| Step Over | `F10` | Execute next stage |
| Step Into | `F11` | Enter sub-pipeline |
| Step Out | `Shift+F11` | Exit sub-pipeline |
| Restart | `Ctrl+Shift+F5` | Restart from beginning |
| Stop | `Shift+F5` | Stop execution |

### Debug Toolbar

```
[▶ Continue] [⏭ Step Over] [⬇ Step Into] [⬆ Step Out] [🔄 Restart] [⏹ Stop]
```

## Step 5: Inspect Variables

When paused, the Variables panel shows:

```
VARIABLES
├── Input
│   ├── url: "https://example.com/article"
│   └── max_length: 150
├── Output (after stage executes)
│   ├── body: {...}
│   └── status_code: 200
├── Context
│   ├── run_id: "run-abc123"
│   ├── stage_id: "fetch"
│   └── pipeline_name: "content-summarizer"
└── Previous Stages
    └── (outputs from completed stages)
```

### Expanding Objects

- Click the arrow to expand nested objects
- Double-click a value to copy it
- Right-click for additional options

## Step 6: Use Watch Expressions

Add expressions to monitor throughout execution:

1. In the Watch panel, click "+"
2. Enter an expression:
   - `{{fetch.output.status_code}}`
   - `{{input.url}}`
   - `{{extract.output.result.length}}`

Watch expressions update as you step through the pipeline.

## Step 7: Debug Console

Evaluate expressions in the Debug Console:

```
> {{fetch.output.body}}
{ "content": "Article text...", "meta": {...} }

> {{input.url.startsWith("https")}}
true

> {{context.run_id}}
"run-abc123"
```

### Useful Expressions

```javascript
// Check stage output
{{fetch.output}}

// Access nested properties
{{fetch.output.body.data[0].name}}

// String operations
{{input.url.replace("http:", "https:")}}

// Conditional checks
{{fetch.output.status_code == 200 ? "OK" : "FAILED"}}
```

## Step 8: Prompt Editor (AI Stages)

When paused at an AI node (generator, critic, etc.), the Prompt Editor activates:

### Viewing Prompts

```
┌─────────────────────────────────────────┐
│ PROMPT EDITOR                           │
├─────────────────────────────────────────┤
│ Stage: summarize                        │
│ Component: generator                    │
├─────────────────────────────────────────┤
│ System Prompt:                          │
│ ┌─────────────────────────────────────┐ │
│ │ You are a concise summarizer...     │ │
│ └─────────────────────────────────────┘ │
│                                         │
│ User Prompt:                            │
│ ┌─────────────────────────────────────┐ │
│ │ Summarize the following content...  │ │
│ └─────────────────────────────────────┘ │
│                                         │
│ [Edit] [Re-run] [Compare]               │
└─────────────────────────────────────────┘
```

### Editing Prompts Live

1. Click "Edit" to enable editing
2. Modify the prompt text
3. Click "Re-run Stage" to execute with new prompt
4. Compare outputs side-by-side

### Prompt Iteration Workflow

1. Set breakpoint on AI stage
2. Start debugging
3. When paused, view the prompt
4. Edit and re-run until satisfied
5. Update the pipeline file with the final prompt
6. Continue execution

### Token Streaming

Watch LLM responses arrive in real-time:

```
Output (streaming):
The article discusses several key points█
```

Enable in settings: `flowmason.debugger.showTokenStream`

## Step 9: Conditional Breakpoints

Breakpoints that only trigger under certain conditions:

1. Right-click an existing breakpoint
2. Select "Edit Breakpoint..."
3. Enter a condition:

```
{{fetch.output.status_code}} != 200
```

The breakpoint only triggers when the condition is true.

### Example Conditions

```javascript
// Break on error status
{{fetch.output.status_code}} >= 400

// Break on empty result
{{extract.output.result.length}} == 0

// Break on specific input
{{input.url.includes("important")}}

// Break on iteration count (in loops)
{{_loop.index}} > 5
```

## Step 10: Exception Breakpoints

Break automatically when errors occur:

1. Open the Breakpoints panel
2. Check "Break on Exceptions"
3. Choose:
   - "All Exceptions" - Any error
   - "Uncaught Exceptions" - Unhandled errors only

### Error Types

When paused on an exception, you can see:

```
VARIABLES
└── _error
    ├── type: "CONNECTIVITY"
    ├── message: "Connection refused"
    ├── stage: "fetch"
    └── details: {...}
```

## Debugging Control Flow

### Conditional Branches

When debugging a `conditional` stage:
1. Variables show the condition value
2. Step Over shows which branch was taken
3. Skipped branches appear grayed in the DAG

### Loops (ForEach)

When debugging a `foreach` stage:
1. Variables show current item and index
2. Step through each iteration
3. Watch expressions track progress

```
VARIABLES
├── _loop
│   ├── index: 2
│   ├── total: 10
│   └── item: {...}
```

### Try/Catch

When debugging a `trycatch` stage:
1. Try stages execute normally
2. On error, catch stages execute
3. Exception breakpoints can pause on the error

## Real-World Debugging Scenarios

### Scenario 1: API Returns Unexpected Data

1. Set breakpoint on the stage using the API response
2. Inspect `{{previous_stage.output}}`
3. Check the actual data structure
4. Update your transform expression

### Scenario 2: AI Output Not As Expected

1. Set breakpoint on AI stage
2. Open Prompt Editor
3. View the actual prompt being sent
4. Edit and iterate until output improves
5. Update pipeline with final prompt

### Scenario 3: Loop Running Too Long

1. Set conditional breakpoint: `{{_loop.index}} > 100`
2. Debug to understand why loop hasn't terminated
3. Check loop exit conditions

### Scenario 4: Intermittent Failures

1. Enable "Break on Exceptions"
2. Run the pipeline multiple times
3. When it breaks, inspect the error context
4. Identify the root cause

## Debug Keyboard Shortcuts Reference

| Action | Mac | Windows/Linux |
|--------|-----|---------------|
| Start Debugging | `F5` | `F5` |
| Toggle Breakpoint | `F9` | `F9` |
| Step Over | `F10` | `F10` |
| Step Into | `F11` | `F11` |
| Step Out | `Shift+F11` | `Shift+F11` |
| Continue | `F5` | `F5` |
| Stop | `Shift+F5` | `Shift+F5` |
| Restart | `Cmd+Shift+F5` | `Ctrl+Shift+F5` |

## Troubleshooting

### Breakpoints Not Working

- Ensure Studio is running
- Check breakpoint is on a valid stage ID
- Verify pipeline path in launch config
- Look for validation errors in Problems panel

### Variables Not Showing

- Wait for stage to complete before inspecting output
- Expand nested objects manually
- Check WebSocket connection in FlowMason output

### Debug Session Disconnects

- Check Studio server is running
- Increase timeout in settings
- Check for network issues

## Next Steps

- [Tutorial 4: Testing Pipelines](./04-testing-pipelines.md) - Write automated tests
- [Tutorial 5: Working with Components](./05-working-with-components.md) - Create custom components


---

## tutorials/04-testing-pipelines.md

# Tutorial 4: Testing Pipelines

This tutorial covers writing and running tests for FlowMason pipelines using VSCode's Test Explorer.

## What You'll Learn

- Creating test files (`.test.json`)
- Writing assertions
- Using mocks
- Running tests from VSCode
- Viewing coverage reports

## Prerequisites

- Completed [Tutorial 2: Building Your First Pipeline](./02-building-first-pipeline.md)
- A pipeline to test
- Studio running

## Test File Format

FlowMason tests are defined in `.test.json` files alongside your pipelines.

### Basic Structure

Create `pipelines/content-summarizer.test.json`:

```json
{
  "name": "Content Summarizer Tests",
  "pipeline": "pipelines/content-summarizer.pipeline.json",
  "tests": [
    {
      "name": "summarizes valid URL",
      "input": {
        "url": "https://example.com/article",
        "max_length": 100
      },
      "assertions": [
        { "path": "output.summary", "type": "string" },
        { "path": "output.summary.length", "greaterThan": 0 }
      ]
    }
  ]
}
```

## Step 1: Create Your First Test

### Test Case Structure

```json
{
  "name": "descriptive test name",
  "input": { /* pipeline input */ },
  "assertions": [ /* what to verify */ ]
}
```

### Example: Happy Path Test

```json
{
  "name": "processes valid input successfully",
  "input": {
    "url": "https://httpbin.org/json"
  },
  "assertions": [
    { "path": "output.summary", "exists": true },
    { "path": "output.summary", "type": "string" },
    { "path": "output.source_url", "equals": "https://httpbin.org/json" }
  ]
}
```

### Example: Error Test

```json
{
  "name": "handles missing URL",
  "input": {},
  "expectError": "VALIDATION"
}
```

## Step 2: Assertion Types

### Equality

```json
{ "path": "output.status", "equals": "success" }
{ "path": "output.count", "equals": 42 }
{ "path": "output.enabled", "equals": true }
```

### Type Checks

```json
{ "path": "output.data", "type": "array" }
{ "path": "output.name", "type": "string" }
{ "path": "output.count", "type": "number" }
{ "path": "output.valid", "type": "boolean" }
{ "path": "output.config", "type": "object" }
```

### Comparisons

```json
{ "path": "output.score", "greaterThan": 0.5 }
{ "path": "output.score", "lessThan": 1.0 }
{ "path": "output.count", "greaterOrEqual": 10 }
{ "path": "output.count", "lessOrEqual": 100 }
```

### String Matching

```json
{ "path": "output.message", "contains": "success" }
{ "path": "output.email", "matches": "^[a-z]+@example\\.com$" }
{ "path": "output.url", "startsWith": "https://" }
{ "path": "output.filename", "endsWith": ".json" }
```

### Array Assertions

```json
{ "path": "output.items", "length": 5 }
{ "path": "output.items", "minLength": 1 }
{ "path": "output.items", "maxLength": 100 }
{ "path": "output.items", "contains": "apple" }
{ "path": "output.items", "notContains": "error" }
```

### Object Assertions

```json
{ "path": "output.data", "hasProperty": "id" }
{ "path": "output.data", "notHasProperty": "password" }
```

### Existence Checks

```json
{ "path": "output.result", "exists": true }
{ "path": "output.error", "exists": false }
{ "path": "output.value", "notNull": true }
```

### Deep Equality

```json
{
  "path": "output.config",
  "deepEquals": {
    "enabled": true,
    "mode": "production"
  }
}
```

### Custom Expressions

```json
{
  "path": "output",
  "expression": "data.length > 0 && data.every(item => item.valid)"
}
```

## Step 3: Stage-Level Testing

Test specific stages, not just final output:

```json
{
  "name": "fetch stage returns 200",
  "input": { "url": "https://httpbin.org/json" },
  "stageAssertions": {
    "fetch": [
      { "path": "output.status_code", "equals": 200 }
    ],
    "extract": [
      { "path": "output.result", "type": "object" }
    ]
  }
}
```

## Step 4: Using Mocks

### Mock HTTP Responses

Avoid hitting real APIs in tests:

```json
{
  "name": "handles API response",
  "mocks": {
    "http-request": {
      "output": {
        "status_code": 200,
        "body": {
          "content": "This is mock content for testing."
        }
      }
    }
  },
  "input": { "url": "https://example.com" },
  "assertions": [
    { "path": "output.summary", "contains": "mock content" }
  ]
}
```

### Mock LLM Responses

Control AI outputs for deterministic tests:

```json
{
  "name": "test summarization",
  "mocks": {
    "generator": {
      "output": {
        "content": "This is a mocked summary.",
        "usage": { "input_tokens": 100, "output_tokens": 20 }
      }
    }
  },
  "input": { "url": "https://example.com" },
  "assertions": [
    { "path": "output.summary", "equals": "This is a mocked summary." }
  ]
}
```

### Mock Multiple Components

```json
{
  "mocks": {
    "http-request": {
      "output": { "status_code": 200, "body": "..." }
    },
    "generator": {
      "output": { "content": "..." }
    },
    "json-transform": {
      "output": { "result": {...} }
    }
  }
}
```

## Step 5: Setup and Teardown

### Global Setup

```json
{
  "name": "API Integration Tests",
  "pipeline": "pipelines/api.pipeline.json",
  "setup": {
    "variables": {
      "API_URL": "https://test.api.example.com",
      "AUTH_TOKEN": "test-token-123"
    }
  },
  "teardown": {
    "cleanup": ["temp_files"]
  },
  "tests": [...]
}
```

### Per-Test Setup

```json
{
  "tests": [
    {
      "name": "with verbose mode",
      "setup": {
        "variables": { "LOG_LEVEL": "debug" }
      },
      "input": {...},
      "assertions": [...]
    }
  ]
}
```

## Step 6: Error Testing

### Expected Error Type

```json
{
  "name": "rejects invalid URL",
  "input": { "url": "not-a-url" },
  "expectError": "VALIDATION"
}
```

### Error Types

| Type | Description |
|------|-------------|
| `VALIDATION` | Input validation failed |
| `COMPONENT` | Component execution error |
| `PROVIDER` | LLM provider error |
| `TIMEOUT` | Execution timed out |
| `CONNECTIVITY` | Network/connection error |
| `CONFIGURATION` | Configuration error |

### Error Message Check

```json
{
  "name": "error message includes details",
  "input": {},
  "expectError": "VALIDATION",
  "errorContains": "url is required"
}
```

## Step 7: Running Tests

### From VSCode Test Explorer

1. Open Test Explorer (`View > Testing`)
2. Your test files appear in the tree
3. Click "Run" on a test suite or individual test
4. View results inline

```
TEST EXPLORER
├── ▼ content-summarizer.test.json
│   ├── ✓ summarizes valid URL (1.2s)
│   ├── ✓ handles missing URL (0.1s)
│   ├── ✓ handles API error (0.3s)
│   └── ✗ handles long content (timeout)
```

### From Command Line

```bash
# Run all tests
fm test

# Run specific test file
fm test pipelines/content-summarizer.test.json

# Run tests matching pattern
fm test --filter "valid URL"

# Run with verbose output
fm test --verbose

# Run with coverage
fm test --coverage
```

### From Context Menu

1. Right-click on a `.test.json` file
2. Select "FlowMason: Run Tests"

### Keyboard Shortcut

- `Cmd+; A` - Run all tests
- `Cmd+; F` - Run tests in current file
- `Cmd+; L` - Run last test

## Step 8: Test Coverage

### Enable Coverage

```bash
fm test --coverage
```

### Coverage Report

```
Coverage Report
───────────────────────────────────────
Pipeline                    Coverage
───────────────────────────────────────
content-summarizer.pipeline.json    85%
  ├── fetch                     100%
  ├── extract                   100%
  ├── summarize                  75%
  └── output                     66%
───────────────────────────────────────
Total                           85%
```

### Coverage in VSCode

- Test Explorer shows per-file coverage
- Editor gutters show covered/uncovered stages (future feature)

## Step 9: Snapshot Testing

Compare output against saved snapshots:

```json
{
  "name": "output matches snapshot",
  "input": { "url": "https://example.com" },
  "snapshot": "tests/snapshots/summarizer-output.json"
}
```

### Update Snapshots

When expected output changes:

```bash
fm test --update-snapshots
```

## Complete Test File Example

`pipelines/content-summarizer.test.json`:

```json
{
  "name": "Content Summarizer Tests",
  "pipeline": "pipelines/content-summarizer.pipeline.json",
  "setup": {
    "variables": {
      "TEST_MODE": "true"
    }
  },
  "tests": [
    {
      "name": "summarizes valid URL",
      "mocks": {
        "http-request": {
          "output": {
            "status_code": 200,
            "body": { "content": "The quick brown fox jumps over the lazy dog. This is a test article about animals and their behaviors." }
          }
        },
        "generator": {
          "output": {
            "content": "An article about animal behavior, specifically foxes and dogs.",
            "usage": { "input_tokens": 50, "output_tokens": 15 }
          }
        }
      },
      "input": {
        "url": "https://example.com/article",
        "max_length": 100
      },
      "assertions": [
        { "path": "output.summary", "type": "string" },
        { "path": "output.summary.length", "greaterThan": 0 },
        { "path": "output.source_url", "equals": "https://example.com/article" }
      ],
      "stageAssertions": {
        "fetch": [
          { "path": "output.status_code", "equals": 200 }
        ]
      }
    },
    {
      "name": "handles missing URL",
      "input": {},
      "expectError": "VALIDATION",
      "errorContains": "url"
    },
    {
      "name": "handles API error gracefully",
      "mocks": {
        "http-request": {
          "error": {
            "type": "CONNECTIVITY",
            "message": "Connection refused"
          }
        }
      },
      "input": {
        "url": "https://invalid.example.com"
      },
      "expectError": "CONNECTIVITY"
    },
    {
      "name": "respects max_length parameter",
      "skip": false,
      "timeout": 30000,
      "mocks": {
        "http-request": {
          "output": {
            "status_code": 200,
            "body": { "content": "Long content here..." }
          }
        },
        "generator": {
          "output": {
            "content": "Short summary.",
            "usage": { "input_tokens": 100, "output_tokens": 5 }
          }
        }
      },
      "input": {
        "url": "https://example.com/long-article",
        "max_length": 50
      },
      "assertions": [
        { "path": "output.summary", "type": "string" }
      ]
    }
  ]
}
```

## Best Practices

### 1. Test the Happy Path

Always have a test for successful execution:

```json
{
  "name": "processes valid input",
  "input": { /* valid input */ },
  "assertions": [ /* verify success */ ]
}
```

### 2. Test Error Cases

```json
{
  "name": "handles empty input",
  "input": {},
  "expectError": "VALIDATION"
}
```

### 3. Use Mocks for External Services

Don't hit real APIs in tests:

```json
{
  "mocks": {
    "http-request": { "output": {...} }
  }
}
```

### 4. Test Individual Stages

Use `stageAssertions` for granular testing:

```json
{
  "stageAssertions": {
    "fetch": [...],
    "transform": [...]
  }
}
```

### 5. Keep Tests Fast

Use mocks and avoid timeouts:

```json
{
  "timeout": 5000,
  "mocks": {...}
}
```

### 6. Use Descriptive Names

```json
// Good
"name": "returns error when URL is malformed"

// Bad
"name": "test 1"
```

### 7. Aim for 80%+ Coverage

```bash
fm test --coverage
```

## CI/CD Integration

### GitHub Actions

```yaml
name: FlowMason Tests

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup FlowMason
        run: |
          pip install flowmason flowmason-studio

      - name: Run Tests
        run: fm test --coverage --reporter json > results.json

      - name: Upload Coverage
        uses: codecov/codecov-action@v3
```

## Next Steps

- [Tutorial 5: Working with Components](./05-working-with-components.md) - Create custom nodes and operators


---

## tutorials/05-working-with-components.md

# Tutorial 5: Working with Components

This tutorial covers creating custom components (nodes and operators) and using built-in FlowMason components.

## What You'll Learn

- Understanding the three component types
- Creating custom AI nodes
- Creating custom operators
- Using built-in control flow components
- Registering and packaging components

## Component Types Overview

FlowMason has three component types:

| Type | Decorator | Purpose | Example |
|------|-----------|---------|---------|
| **Node** | `@node` | AI-powered operations | Text generation, analysis |
| **Operator** | `@operator` | Deterministic utilities | HTTP requests, transforms |
| **Control Flow** | `@control_flow` | Execution flow control | Conditionals, loops |

## Part 1: Creating a Custom Node

Nodes are AI-powered components that use LLM providers.

### Step 1: Create the Node File

Create `components/nodes/keyword_extractor.py`:

```python
from flowmason_core import (
    node, BaseNode, NodeInput, NodeOutput, Context
)
from pydantic import Field
from typing import List


@node(
    name="keyword-extractor",
    description="Extract keywords from text using AI",
    category="analysis",
    recommended_providers={"anthropic": ["claude-sonnet-4-20250514"]},
    timeout=60,
    max_retries=3
)
class KeywordExtractorNode(BaseNode):
    """Extracts relevant keywords from text content."""

    class Input(NodeInput):
        text: str = Field(
            description="Text to extract keywords from"
        )
        max_keywords: int = Field(
            default=10,
            ge=1,
            le=50,
            description="Maximum number of keywords to extract"
        )
        include_scores: bool = Field(
            default=False,
            description="Include relevance scores for keywords"
        )

    class Output(NodeOutput):
        keywords: List[str] = Field(
            description="Extracted keywords"
        )
        scores: List[float] = Field(
            default=[],
            description="Relevance scores (if requested)"
        )

    async def execute(self, input: Input, context: Context) -> Output:
        # Build the prompt
        prompt = f"""Extract the {input.max_keywords} most important keywords
from the following text. Return them as a JSON array.

Text:
{input.text}

{"Include a relevance score (0-1) for each keyword." if input.include_scores else ""}

Return format:
{{"keywords": ["word1", "word2"], "scores": [0.9, 0.8]}}
"""

        # Call the LLM
        response = await context.llm.generate(
            system_prompt="You are a keyword extraction expert. Always return valid JSON.",
            prompt=prompt,
            temperature=0.3,
            max_tokens=500
        )

        # Parse the response
        import json
        result = json.loads(response.content)

        return self.Output(
            keywords=result["keywords"][:input.max_keywords],
            scores=result.get("scores", []) if input.include_scores else []
        )
```

### Step 2: Node Decorator Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | str | Yes | Unique component name |
| `description` | str | Yes | Human-readable description |
| `category` | str | No | Category for organization |
| `recommended_providers` | dict | No | Suggested LLM providers/models |
| `timeout` | int | No | Execution timeout in seconds (default: 60) |
| `max_retries` | int | No | Maximum retry attempts (default: 3) |

### Step 3: Use the Node in a Pipeline

```json
{
  "id": "extract_keywords",
  "component_type": "keyword-extractor",
  "depends_on": ["fetch_content"],
  "config": {
    "text": "{{fetch_content.output.body}}",
    "max_keywords": 15,
    "include_scores": true
  }
}
```

## Part 2: Creating a Custom Operator

Operators are deterministic, non-AI components.

### Step 1: Create the Operator File

Create `components/operators/text_cleaner.py`:

```python
from flowmason_core import (
    operator, BaseOperator, OperatorInput, OperatorOutput, Context
)
from pydantic import Field
import re
from typing import Optional


@operator(
    name="text-cleaner",
    description="Clean and normalize text content",
    category="transform",
    timeout=30
)
class TextCleanerOperator(BaseOperator):
    """Removes HTML tags, extra whitespace, and normalizes text."""

    class Input(OperatorInput):
        text: str = Field(
            description="Text to clean"
        )
        remove_html: bool = Field(
            default=True,
            description="Remove HTML tags"
        )
        remove_urls: bool = Field(
            default=False,
            description="Remove URLs"
        )
        lowercase: bool = Field(
            default=False,
            description="Convert to lowercase"
        )
        max_length: Optional[int] = Field(
            default=None,
            description="Truncate to max length"
        )

    class Output(OperatorOutput):
        text: str = Field(
            description="Cleaned text"
        )
        original_length: int = Field(
            description="Original text length"
        )
        cleaned_length: int = Field(
            description="Cleaned text length"
        )

    async def execute(self, input: Input, context: Context) -> Output:
        text = input.text
        original_length = len(text)

        # Remove HTML tags
        if input.remove_html:
            text = re.sub(r'<[^>]+>', '', text)

        # Remove URLs
        if input.remove_urls:
            text = re.sub(r'https?://\S+', '', text)

        # Normalize whitespace
        text = re.sub(r'\s+', ' ', text).strip()

        # Lowercase
        if input.lowercase:
            text = text.lower()

        # Truncate
        if input.max_length and len(text) > input.max_length:
            text = text[:input.max_length] + "..."

        return self.Output(
            text=text,
            original_length=original_length,
            cleaned_length=len(text)
        )
```

### Step 2: Operator Decorator Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | str | Yes | Unique component name |
| `description` | str | Yes | Human-readable description |
| `category` | str | No | Category for organization |
| `timeout` | int | No | Execution timeout in seconds (default: 30) |

### Step 3: Use the Operator in a Pipeline

```json
{
  "id": "clean_content",
  "component_type": "text-cleaner",
  "depends_on": ["fetch"],
  "config": {
    "text": "{{fetch.output.body}}",
    "remove_html": true,
    "remove_urls": true,
    "max_length": 10000
  }
}
```

## Part 3: Using Built-in Control Flow Components

FlowMason provides 6 built-in control flow components.

### Conditional (If/Else)

```json
{
  "id": "check_status",
  "component_type": "conditional",
  "depends_on": ["fetch"],
  "config": {
    "condition": "{{fetch.output.status_code}} == 200",
    "true_branch": "process_success",
    "false_branch": "handle_error"
  }
}
```

### Router (Switch/Case)

```json
{
  "id": "route_by_type",
  "component_type": "router",
  "depends_on": ["detect_type"],
  "config": {
    "value": "{{detect_type.output.content_type}}",
    "routes": {
      "text/html": "process_html",
      "application/json": "process_json",
      "text/plain": "process_text"
    },
    "default": "process_generic"
  }
}
```

### ForEach (Loop)

```json
{
  "id": "process_items",
  "component_type": "foreach",
  "depends_on": ["get_items"],
  "config": {
    "items": "{{get_items.output.items}}",
    "item_variable": "item",
    "stages": ["transform_item", "save_item"],
    "parallel": true,
    "max_concurrency": 5
  }
}
```

Inside loop stages, access the current item:
```json
{
  "id": "transform_item",
  "config": {
    "data": "{{item}}"
  }
}
```

### TryCatch (Error Handling)

```json
{
  "id": "safe_operation",
  "component_type": "trycatch",
  "config": {
    "try_stages": ["risky_fetch", "process"],
    "catch_stages": ["log_error", "use_fallback"],
    "finally_stages": ["cleanup"],
    "on_error": "continue"
  }
}
```

In catch stages, access error info:
```json
{
  "id": "log_error",
  "component_type": "logger",
  "config": {
    "message": "Error: {{_error.message}}",
    "data": {
      "type": "{{_error.type}}",
      "stage": "{{_error.stage}}"
    }
  }
}
```

### SubPipeline (Composition)

```json
{
  "id": "run_etl",
  "component_type": "subpipeline",
  "config": {
    "pipeline": "pipelines/etl.pipeline.json",
    "input": {
      "source": "{{input.data_source}}",
      "destination": "{{input.output_path}}"
    }
  }
}
```

### Return (Early Exit)

```json
{
  "id": "early_exit",
  "component_type": "return",
  "depends_on": ["validate"],
  "config": {
    "condition": "{{validate.output.valid}} == false",
    "value": {
      "error": "Validation failed",
      "details": "{{validate.output.errors}}"
    }
  }
}
```

## Part 4: Built-in Operators

### HTTP Request

```json
{
  "id": "fetch_api",
  "component_type": "http-request",
  "config": {
    "url": "https://api.example.com/data",
    "method": "POST",
    "headers": {
      "Authorization": "Bearer {{input.api_key}}"
    },
    "body": {
      "query": "{{input.search_term}}"
    },
    "timeout": 30
  }
}
```

### JSON Transform

```json
{
  "id": "extract_data",
  "component_type": "json-transform",
  "config": {
    "data": "{{fetch.output.body}}",
    "expression": "results[*].{name: name, id: id}"
  }
}
```

### Filter

```json
{
  "id": "filter_active",
  "component_type": "filter",
  "config": {
    "data": "{{items.output.list}}",
    "condition": "item.status == 'active'"
  }
}
```

### Schema Validate

```json
{
  "id": "validate_input",
  "component_type": "schema-validate",
  "config": {
    "data": "{{input}}",
    "schema": {
      "type": "object",
      "required": ["url"],
      "properties": {
        "url": { "type": "string", "format": "uri" }
      }
    }
  }
}
```

### Logger

```json
{
  "id": "log_progress",
  "component_type": "logger",
  "config": {
    "level": "info",
    "message": "Processing {{input.url}}",
    "data": {
      "timestamp": "{{context.timestamp}}",
      "run_id": "{{context.run_id}}"
    }
  }
}
```

## Part 5: Built-in AI Nodes

### Generator

```json
{
  "id": "generate_content",
  "component_type": "generator",
  "config": {
    "system_prompt": "You are a helpful assistant.",
    "prompt": "Write about {{input.topic}}",
    "temperature": 0.7,
    "max_tokens": 1000
  }
}
```

### Critic

```json
{
  "id": "evaluate_content",
  "component_type": "critic",
  "config": {
    "content": "{{generate.output.content}}",
    "criteria": ["accuracy", "clarity", "engagement"],
    "rubric": "Score each criterion 1-10 with explanation"
  }
}
```

### Improver

```json
{
  "id": "improve_content",
  "component_type": "improver",
  "config": {
    "content": "{{generate.output.content}}",
    "feedback": "{{critic.output.feedback}}",
    "instructions": "Address the feedback while maintaining the original tone"
  }
}
```

### Selector

```json
{
  "id": "select_best",
  "component_type": "selector",
  "config": {
    "options": "{{generate_variants.output.variants}}",
    "criteria": "Select the most engaging and accurate option",
    "return_reasoning": true
  }
}
```

### Synthesizer

```json
{
  "id": "combine_sources",
  "component_type": "synthesizer",
  "config": {
    "sources": [
      "{{source1.output.content}}",
      "{{source2.output.content}}"
    ],
    "instructions": "Combine into a coherent summary"
  }
}
```

## Part 6: Registering Components

### Project Configuration

In `flowmason.json`:

```json
{
  "components": {
    "include": [
      "components/**/*.py"
    ]
  }
}
```

### Verify Registration

```bash
# List all registered components
fm list --components

# Check specific component
fm validate components/nodes/keyword_extractor.py
```

### In VSCode

Components appear in the FlowMason sidebar under:
- COMPONENTS > Nodes > keyword-extractor
- COMPONENTS > Operators > text-cleaner

## Part 7: Packaging Components

### Create a Package

```bash
fm pack --output my-components-1.0.0.fmpkg
```

### Package Contents

```
my-components-1.0.0.fmpkg
├── manifest.json
├── components/
│   ├── nodes/
│   │   └── keyword_extractor.py
│   └── operators/
│       └── text_cleaner.py
└── README.md
```

### Install Package

```bash
fm install my-components-1.0.0.fmpkg
```

## Part 8: Testing Components

### Unit Test for Node

```python
import pytest
from components.nodes.keyword_extractor import KeywordExtractorNode

@pytest.mark.asyncio
async def test_keyword_extraction():
    node = KeywordExtractorNode()

    # Mock context with LLM
    context = MockContext(llm_response='{"keywords": ["test", "example"]}')

    input_data = node.Input(
        text="This is a test example text.",
        max_keywords=5
    )

    output = await node.execute(input_data, context)

    assert len(output.keywords) <= 5
    assert "test" in output.keywords
```

### Unit Test for Operator

```python
import pytest
from components.operators.text_cleaner import TextCleanerOperator

@pytest.mark.asyncio
async def test_text_cleaning():
    operator = TextCleanerOperator()

    input_data = operator.Input(
        text="<p>Hello  World</p>",
        remove_html=True
    )

    output = await operator.execute(input_data, None)

    assert output.text == "Hello World"
    assert output.cleaned_length < output.original_length
```

## Best Practices

### 1. Clear Input/Output Schemas

```python
class Input(NodeInput):
    text: str = Field(description="Input text to process")
    # Always include descriptions
```

### 2. Sensible Defaults

```python
max_keywords: int = Field(default=10, ge=1, le=50)
```

### 3. Proper Error Handling

```python
async def execute(self, input: Input, context: Context) -> Output:
    try:
        result = await self._do_work(input)
        return self.Output(result=result)
    except ValueError as e:
        raise ValidationError(f"Invalid input: {e}")
```

### 4. Logging for Debugging

```python
async def execute(self, input: Input, context: Context) -> Output:
    context.logger.info(f"Processing {len(input.text)} characters")
    # ... do work
    context.logger.debug(f"Found {len(keywords)} keywords")
```

### 5. Respect Timeouts

For long operations, check for cancellation:

```python
async def execute(self, input: Input, context: Context) -> Output:
    for item in items:
        if context.cancellation_token.is_cancelled:
            raise CancellationError("Operation cancelled")
        await self._process_item(item)
```

## Summary

You've learned to:
- Create custom AI nodes with the `@node` decorator
- Create custom operators with the `@operator` decorator
- Use built-in control flow components
- Work with built-in operators and nodes
- Register and package components
- Test components

## Next Steps

- Explore the [API Reference](../04-core-framework/decorators/node.md) for detailed decorator options
- Read about [Pipeline Patterns](../03-concepts/pipelines.md) for advanced composition
- Check [Testing Guide](./04-testing-pipelines.md) for comprehensive testing strategies


---

## tutorials/README.md

# FlowMason Tutorials

Step-by-step guides to help you master FlowMason.

## Tutorial Path

Follow these tutorials in order for the best learning experience:

| # | Tutorial | Duration | What You'll Learn |
|---|----------|----------|-------------------|
| 1 | [Getting Started](./01-getting-started.md) | 15 min | Install extension, set up project |
| 2 | [Building Your First Pipeline](./02-building-first-pipeline.md) | 30 min | Create a 3-stage AI pipeline |
| 3 | [Debugging Pipelines](./03-debugging-pipelines.md) | 25 min | Breakpoints, stepping, prompt editing |
| 4 | [Testing Pipelines](./04-testing-pipelines.md) | 25 min | Write tests, use mocks, coverage |
| 5 | [Working with Components](./05-working-with-components.md) | 35 min | Create custom nodes and operators |

**Total Time:** ~2.5 hours

## Prerequisites

Before starting:
- VSCode 1.85.0 or later
- Python 3.11 or later
- Basic understanding of JSON and Python

## Quick Start

If you're in a hurry:

1. **Install** (5 min)
   ```bash
   code --install-extension flowmason-0.10.0.vsix
   pip install flowmason flowmason-studio flowmason-lab
   ```

2. **Create Project** (2 min)
   ```bash
   mkdir my-project && cd my-project
   fm init
   fm studio start
   code .
   ```

3. **Run a Pipeline** (1 min)
   - Open any `.pipeline.json` file
   - Press `F5` to run

## Tutorial Summaries

### Tutorial 1: Getting Started

Learn how to:
- Install the FlowMason VSCode extension
- Set up Python dependencies
- Initialize a FlowMason project
- Start the Studio backend
- Navigate the VSCode interface

### Tutorial 2: Building Your First Pipeline

Learn how to:
- Create pipeline files (`.pipeline.json`)
- Add stages using the visual editor
- Configure component inputs
- Use template expressions (`{{input.field}}`)
- Run pipelines from VSCode

### Tutorial 3: Debugging Pipelines

Learn how to:
- Set breakpoints on stages
- Step through execution (F10, F11)
- Inspect variables and outputs
- Use the Prompt Editor for AI stages
- Handle errors and exceptions

### Tutorial 4: Testing Pipelines

Learn how to:
- Create test files (`.test.json`)
- Write assertions for outputs
- Mock external services and LLMs
- Run tests from Test Explorer
- Generate coverage reports

### Tutorial 5: Working with Components

Learn how to:
- Create custom AI nodes (`@node`)
- Create custom operators (`@operator`)
- Use built-in control flow components
- Register components in your project
- Package components for distribution

## Additional Resources

- [Reference Documentation](../04-core-framework/decorators/node.md)
- [Concepts Guide](../03-concepts/pipelines.md)
- [Studio API Reference](../06-studio/overview.md)
- [VSCode Extension Guide](../07-vscode-extension/overview.md)

## Getting Help

- Check the [Troubleshooting](../07-vscode-extension/overview.md#troubleshooting) section
- View FlowMason output: `View > Output > FlowMason`
- Run diagnostics: `fm validate pipelines/`

## Feedback

Found an issue or have suggestions? Open an issue on GitHub.

---

## Full Document Index

All documentation files in this `fmdocs` folder:

### Status

- [00-status/future-features.md](00-status/future-features.md)
- [00-status/implementation-status.md](00-status/implementation-status.md)
- [00-status/remaining-work.md](00-status/remaining-work.md)

### Vision

- [01-vision/README.md](01-vision/README.md)
- [01-vision/product-vision.md](01-vision/product-vision.md)
- [01-vision/hybrid-model.md](01-vision/hybrid-model.md)
- [01-vision/edition-tiers.md](01-vision/edition-tiers.md)
- [01-vision/roadmap.md](01-vision/roadmap.md)
- [01-vision/p5-p6-roadmap.md](01-vision/p5-p6-roadmap.md)

### Getting Started

- [02-getting-started/installation.md](02-getting-started/installation.md)
- [02-getting-started/quickstart.md](02-getting-started/quickstart.md)

### Concepts

- [03-concepts/architecture-overview.md](03-concepts/architecture-overview.md)
- [03-concepts/pipelines.md](03-concepts/pipelines.md)
- [03-concepts/nodes.md](03-concepts/nodes.md)
- [03-concepts/operators.md](03-concepts/operators.md)
- [03-concepts/control-flow.md](03-concepts/control-flow.md)
- [03-concepts/diff-merge.md](03-concepts/diff-merge.md)
- [03-concepts/inheritance.md](03-concepts/inheritance.md)
- [03-concepts/testing.md](03-concepts/testing.md)

### Core Framework

- [04-core-framework/decorators/node.md](04-core-framework/decorators/node.md)
- [04-core-framework/decorators/operator.md](04-core-framework/decorators/operator.md)
- [04-core-framework/decorators/control-flow.md](04-core-framework/decorators/control-flow.md)

### SDKs

- [05-sdk/python-sdk.md](05-sdk/python-sdk.md)
- [05-sdk/typescript-sdk.md](05-sdk/typescript-sdk.md)
- [05-sdk/react-hooks-sdk.md](05-sdk/react-hooks-sdk.md)

### Security

- [05-security/secrets-management.md](05-security/secrets-management.md)
- [05-security/pipeline-permissions.md](05-security/pipeline-permissions.md)
- [05-security/secrets-rotation-audit.md](05-security/secrets-rotation-audit.md)

### Studio

- [06-studio/overview.md](06-studio/overview.md)
- [06-studio/api/input-output.md](06-studio/api/input-output.md)
- [06-studio/docker.md](06-studio/docker.md)
- [06-studio/usage-tracking.md](06-studio/usage-tracking.md)
- [06-studio/system-diagnostics.md](06-studio/system-diagnostics.md)
- [06-studio/webhooks.md](06-studio/webhooks.md)
- [06-studio/analytics.md](06-studio/analytics.md)
- [06-studio/ai-insights.md](06-studio/ai-insights.md)
- [06-studio/ai-copilot.md](06-studio/ai-copilot.md)
- [06-studio/collaboration.md](06-studio/collaboration.md)
- [06-studio/component-visual.md](06-studio/component-visual.md)
- [06-studio/debugging.md](06-studio/debugging.md)
- [06-studio/event-triggers.md](06-studio/event-triggers.md)
- [06-studio/jwt-tokens.md](06-studio/jwt-tokens.md)
- [06-studio/marketplace.md](06-studio/marketplace.md)
- [06-studio/mcp-api.md](06-studio/mcp-api.md)
- [06-studio/mcp-assistant.md](06-studio/mcp-assistant.md)
- [06-studio/mobile-app.md](06-studio/mobile-app.md)
- [06-studio/multi-region.md](06-studio/multi-region.md)
- [06-studio/natural-language-builder.md](06-studio/natural-language-builder.md)
- [06-studio/oauth.md](06-studio/oauth.md)
- [06-studio/prompt-library.md](06-studio/prompt-library.md)
- [06-studio/prompt-ab-testing.md](06-studio/prompt-ab-testing.md)
- [06-studio/scheduling.md](06-studio/scheduling.md)
- [06-studio/template-gallery.md](06-studio/template-gallery.md)
- [06-studio/versioning.md](06-studio/versioning.md)

### Integrations

- [07-integrations/mcp-server.md](07-integrations/mcp-server.md)
- [07-integrations/mcp-client-operators.md](07-integrations/mcp-client-operators.md)
- [07-integrations/mcp-ai-generation.md](07-integrations/mcp-ai-generation.md)
- [07-integrations/opentelemetry.md](07-integrations/opentelemetry.md)
- [07-integrations/remote-registry.md](07-integrations/remote-registry.md)
- [07-integrations/vscode-mcp.md](07-integrations/vscode-mcp.md)

### Packaging & Deployment

- [08-packaging-deployment/distribution-strategy.md](08-packaging-deployment/distribution-strategy.md)
- [08-packaging-deployment/edge-deployment.md](08-packaging-deployment/edge-deployment.md)
- [08-packaging-deployment/federation.md](08-packaging-deployment/federation.md)
- [08-packaging-deployment/kubernetes.md](08-packaging-deployment/kubernetes.md)
- [08-packaging-deployment/publishing-to-pypi.md](08-packaging-deployment/publishing-to-pypi.md)

### Debugging & Testing

- [09-debugging-testing/debugging/current-debugging.md](09-debugging-testing/debugging/current-debugging.md)
- [09-debugging-testing/debugging/visual-debugging.md](09-debugging-testing/debugging/visual-debugging.md)
- [09-debugging-testing/testing/pipeline-testing.md](09-debugging-testing/testing/pipeline-testing.md)

### Architecture

- [10-architecture/system-overview.md](10-architecture/system-overview.md)
- [10-architecture/core/execution-engine.md](10-architecture/core/execution-engine.md)

### Tutorials

- [tutorials/README.md](tutorials/README.md)
- [tutorials/01-getting-started.md](tutorials/01-getting-started.md)
- [tutorials/02-building-first-pipeline.md](tutorials/02-building-first-pipeline.md)
- [tutorials/03-debugging-pipelines.md](tutorials/03-debugging-pipelines.md)
- [tutorials/04-testing-pipelines.md](tutorials/04-testing-pipelines.md)
- [tutorials/05-working-with-components.md](tutorials/05-working-with-components.md)


---

## 01-vision/p5-p6-roadmap.md

# FlowMason P5-P6 Roadmap

**Version:** Implementation Complete
**Date:** December 2025
**Status:** ✅ All Features Implemented

---

## Executive Summary

This roadmap covers 9 future features organized into two new milestones:
- **P5 - Platform Evolution**: Infrastructure, developer experience, and AI integration
- **P6 - Distributed Execution**: Edge deployment and federated execution

All features build on the existing FlowMason architecture and are now part of v1.0.0.

---

## Feature Dependencies Graph

```
                    ┌─────────────────────────────────────────────┐
                    │              P5 - Platform Evolution         │
                    ├─────────────────────────────────────────────┤
                    │                                             │
  ┌─────────────────┼──────────────────┐                         │
  │                 │                  │                         │
  ▼                 ▼                  ▼                         │
┌─────────┐   ┌──────────┐   ┌─────────────────┐                │
│Pipeline │   │Visual    │   │AI Co-pilot      │                │
│Inherit- │   │Diff/Merge│   │Integration      │                │
│ance     │   │          │   │                 │                │
└────┬────┘   └────┬─────┘   └────────┬────────┘                │
     │             │                  │                         │
     │             │                  ▼                         │
     │             │         ┌─────────────────┐                │
     │             │         │Natural Language │                │
     │             │         │Triggers         │                │
     │             │         └─────────────────┘                │
     │             │                                            │
     │             ▼                                            │
     │      ┌──────────────┐   ┌─────────────────┐              │
     │      │Visual Debug  │   │Kubernetes       │              │
     │      │(Animated)    │   │Operator         │              │
     │      └──────────────┘   └─────────────────┘              │
     │                                                          │
     └──────────────────────────────────────────────────────────┘

                    ┌─────────────────────────────────────────────┐
                    │           P6 - Distributed Execution         │
                    ├─────────────────────────────────────────────┤
                    │                                             │
                    │   ┌─────────────┐                           │
                    │   │Edge         │                           │
                    │   │Deployment   │                           │
                    │   └──────┬──────┘                           │
                    │          │                                  │
                    │          ▼                                  │
                    │   ┌─────────────┐                           │
                    │   │Federated    │                           │
                    │   │Execution    │                           │
                    │   └─────────────┘                           │
                    │                                             │
                    │   ┌─────────────┐                           │
                    │   │Mobile       │ (Independent)             │
                    │   │Companion    │                           │
                    │   └─────────────┘                           │
                    └─────────────────────────────────────────────┘
```

---

## Milestone Overview

| Milestone | Features | Total Effort |
|-----------|----------|--------------|
| **P5 - Platform Evolution** | 6 features | 300-420 hours |
| **P6 - Distributed Execution** | 3 features | 220-280 hours |
| **Total** | 9 features | 520-680 hours |

---

## P5 - Platform Evolution

### 5.1 Pipeline Inheritance & Composition
**Effort:** High (40-60 hours) | **Priority:** 1 | **Status:** ✅ Complete

Enable pipelines to extend base pipelines and compose reusable sub-pipelines.

#### Concept
```json
// base-etl.pipeline.json
{
  "name": "base-etl",
  "abstract": true,
  "stages": [
    { "id": "validate", "component_type": "schema_validate" },
    { "id": "transform", "component_type": "abstract" },
    { "id": "output", "component_type": "logger" }
  ]
}

// customer-etl.pipeline.json
{
  "name": "customer-etl",
  "extends": "base-etl",
  "overrides": {
    "transform": {
      "component_type": "json_transform",
      "config": { "mapping": "..." }
    }
  }
}
```

#### New Files
```
core/flowmason_core/inheritance/
├── __init__.py
├── resolver.py          # Resolves inheritance chain
├── merger.py            # Merges parent/child configs
└── validator.py         # Validates inheritance rules
```

#### Schema Changes
- `extends`: Parent pipeline reference
- `abstract`: Cannot be executed directly
- `overrides`: Stage overrides by ID
- `compositions`: Inline sub-pipeline references

#### Implementation Steps
1. Add `InheritanceResolver` class
2. Add `PipelineMerger` for parent/child merging
3. Update `DAGExecutor` for composition stages
4. Add circular inheritance validation
5. Update VSCode extension visualization
6. Add `fm validate --check-inheritance` CLI

---

### 5.2 Visual Pipeline Diff & Merge
**Effort:** High (50-70 hours) | **Priority:** 2 | **Status:** ✅ Complete

Git-style diff and merge for pipeline files with visual representation.

#### Concept
```
┌─────────────────────────────────────────────────────────────────┐
│  Pipeline Diff: main.pipeline.json                              │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────┐     ┌─────────┐     ┌─────────┐   BASE            │
│  │ fetch   │────▶│ process │────▶│ output  │                   │
│  └─────────┘     └─────────┘     └─────────┘                   │
│                                                                 │
│  ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐   │
│  │ fetch   │────▶│ validate│────▶│ process │────▶│ output  │   │
│  └─────────┘     └─────────┘     └─────────┘     └─────────┘   │
│                  ▲ ADDED                                 THEIRS │
├─────────────────────────────────────────────────────────────────┤
│  + Added stage: validate (schema_validate)                      │
│  ~ Modified: process.config.temperature: 0.7 → 0.9              │
└─────────────────────────────────────────────────────────────────┘
```

#### New Files
```
core/flowmason_core/diff/
├── __init__.py
├── pipeline_diff.py      # Structural diff
├── stage_diff.py         # Stage-level diff
└── merge.py              # Three-way merge

vscode-extension/src/diff/
├── pipelineDiffProvider.ts
├── pipelineMergeProvider.ts
└── diffDecorations.ts
```

#### Implementation Steps
1. Implement `PipelineDiffer` class
2. Implement `PipelineMerger` with three-way merge
3. Create VSCode custom diff editor
4. Add visual DAG diff decorations
5. Integrate with git hooks
6. Add `fm diff` and `fm merge` CLI

---

### 5.3 AI Co-pilot Integration
**Effort:** High (60-80 hours) | **Priority:** 3 | **Status:** ✅ Complete

Deep AI integration for pipeline design assistance.

#### Concept
```
┌─────────────────────────────────────────────────────────────────┐
│  AI Co-pilot                                              [Ask] │
├─────────────────────────────────────────────────────────────────┤
│  User: "Add error handling to the API call stage"               │
│                                                                 │
│  Co-pilot: I'll wrap the http-request stage in a trycatch       │
│  with retry logic. Here's my suggestion:                        │
│                                                                 │
│  + trycatch: api-with-retry                                     │
│    ├── try: http-request (existing)                             │
│    ├── catch: error-handler (new)                               │
│    └── retry: 3 attempts, exponential backoff                   │
│                                                                 │
│  [Apply Changes]  [Modify]  [Explain]  [Reject]                │
└─────────────────────────────────────────────────────────────────┘
```

#### API Endpoints
```
POST /api/v1/copilot/suggest     # Get AI suggestion
POST /api/v1/copilot/explain     # Explain pipeline/stage
POST /api/v1/copilot/generate    # Generate from description
POST /api/v1/copilot/optimize    # Suggest optimizations
POST /api/v1/copilot/debug       # Help debug issues
```

#### New Files
```
core/flowmason_core/copilot/
├── __init__.py
├── context.py            # Pipeline context for LLM
├── prompts.py            # System prompts
├── suggestions.py        # Suggestion generation
└── applier.py            # Apply suggestions

studio/flowmason_studio/api/routes/copilot.py
studio/flowmason_studio/services/copilot_service.py

vscode-extension/src/copilot/
├── copilotPanel.ts       # Sidebar panel
├── inlineAssist.ts       # Inline suggestions
└── commands.ts           # Co-pilot commands
```

#### Implementation Steps
1. Create `CopilotService` with Claude/GPT
2. Design context serialization
3. Implement suggestion parsing/validation
4. Create VSCode sidebar panel
5. Add inline suggestions in DAG canvas
6. Add "explain this" hover
7. Add Cmd+K keyboard shortcuts

---

### 5.4 Natural Language Triggers
**Effort:** Medium (30-40 hours) | **Priority:** 4 | **Status:** ✅ Complete

Trigger pipelines using natural language commands.

#### Usage
```bash
# CLI
fm run "process the sales data from yesterday"
fm run "generate a summary of customer feedback"

# API
POST /api/v1/run/natural
{
  "command": "send daily report to the marketing team",
  "context": { "date": "2025-12-14" }
}
```

#### Pipeline Metadata
```json
{
  "name": "daily-sales-report",
  "triggers": {
    "natural_language": {
      "patterns": [
        "generate sales report",
        "sales summary for {date}"
      ],
      "entities": {
        "date": { "type": "date", "default": "today" }
      }
    }
  }
}
```

#### New Files
```
core/flowmason_core/nlp/
├── __init__.py
├── intent_parser.py      # Parse NL to intent
├── pipeline_matcher.py   # Match intent to pipeline
└── input_extractor.py    # Extract inputs

studio/flowmason_studio/api/routes/natural.py
studio/flowmason_studio/services/nl_service.py
```

---

### 5.5 Visual Debugging (Animated Execution)
**Effort:** Medium (40-50 hours) | **Priority:** 5 | **Status:** ✅ Complete

Animated visualization of pipeline execution flow.

#### Concept
```
┌─────────────────────────────────────────────────────────────────┐
│  Execution Visualization                          [▶ Play] [⏸] │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────┐  ═══▶  ┌─────────┐  ───▶  ┌─────────┐            │
│  │ fetch   │  data  │ process │        │ output  │            │
│  │ ✓ 1.2s  │  ════▶ │ ⟳ 45%   │        │ ○ wait  │            │
│  └─────────┘        └─────────┘        └─────────┘            │
│                          │                                      │
│                     Tokens: 234/1000                           │
│                     "Processing customer..."                    │
│                                                                 │
│  Timeline: ═══════════════●═══════════════════════════════     │
│            0s            2.5s                           10s     │
└─────────────────────────────────────────────────────────────────┘
```

#### Features
- Data flow arrows with animations
- Token streaming overlay on LLM stages
- Timeline scrubber for replay
- Speed controls (0.5x, 1x, 2x, 4x)
- Export recordings as video/GIF

#### New Files
```
vscode-extension/src/visualization/
├── executionAnimator.ts
├── dataFlowRenderer.ts
├── tokenStreamOverlay.ts
└── timelineController.ts

studio/frontend/src/components/
├── ExecutionVisualization.tsx
├── DataFlowAnimation.tsx
└── TimelinePlayer.tsx
```

---

### 5.6 Kubernetes Operator
**Effort:** Very High (80-100 hours) | **Priority:** 6 | **Status:** ✅ Complete

Deploy and manage FlowMason pipelines as Kubernetes resources.

#### Custom Resource Definition
```yaml
apiVersion: flowmason.io/v1
kind: Pipeline
metadata:
  name: data-processor
  namespace: production
spec:
  source:
    configMap: data-processor-config
  schedule: "0 * * * *"
  resources:
    requests:
      memory: "256Mi"
      cpu: "100m"
  env:
    - name: ANTHROPIC_API_KEY
      valueFrom:
        secretKeyRef:
          name: llm-secrets
          key: anthropic-key
```

#### New Repository: `flowmason-operator/`
```
flowmason-operator/
├── api/v1/
│   ├── pipeline_types.go
│   ├── pipelinerun_types.go
│   └── groupversion_info.go
├── controllers/
│   ├── pipeline_controller.go
│   └── pipelinerun_controller.go
├── config/
│   ├── crd/bases/
│   ├── rbac/
│   └── manager/
├── Dockerfile
├── Makefile
└── go.mod
```

#### Custom Resources
1. `Pipeline` - Pipeline definition and scheduling
2. `PipelineRun` - Individual execution instance
3. `PipelineTemplate` - Reusable templates

---

## P6 - Distributed Execution

### 6.1 Edge Deployment
**Effort:** High (60-80 hours) | **Priority:** 7 | **Status:** ✅ Complete

Run pipelines on edge devices with limited connectivity.

#### Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│                         CLOUD                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  FlowMason Studio (Central)                              │   │
│  │  - Pipeline registry                                     │   │
│  │  - Execution history sync                                │   │
│  │  - Edge device management                                │   │
│  └────────────────────────┬────────────────────────────────┘   │
└───────────────────────────┼─────────────────────────────────────┘
                            │ Sync (when connected)
        ┌───────────────────┼───────────────────┐
        ▼                   ▼                   ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│  Edge Node 1  │   │  Edge Node 2  │   │  Edge Node 3  │
│  (Raspberry)  │   │  (Jetson)     │   │  (Industrial) │
│  ┌─────────┐  │   │  ┌─────────┐  │   │  ┌─────────┐  │
│  │Pipeline │  │   │  │Pipeline │  │   │  │Pipeline │  │
│  │Cache    │  │   │  │Cache    │  │   │  │Cache    │  │
│  └─────────┘  │   │  └─────────┘  │   │  └─────────┘  │
└───────────────┘   └───────────────┘   └───────────────┘
```

#### New Package: `flowmason-edge/`
```
flowmason-edge/
├── runtime/
│   ├── edge_executor.py      # Lightweight executor
│   ├── offline_cache.py      # Pipeline/model caching
│   └── sync_manager.py       # Cloud sync
├── adapters/
│   ├── local_llm.py          # Ollama/llama.cpp
│   └── quantized.py          # Quantized models
├── deployment/
│   ├── docker-arm64.dockerfile
│   └── install.sh
└── cli/edge_cli.py
```

#### Features
- Offline-first execution
- Local LLM support (Ollama, llama.cpp)
- Model caching and quantization
- Store-and-forward for results
- Resource-constrained execution

---

### 6.2 Federated Execution
**Effort:** Very High (100-120 hours) | **Priority:** 8 | **Status:** ✅ Complete

Distribute pipeline execution across multiple clouds/regions.

#### Concept
```
┌─────────────────────────────────────────────────────────────────┐
│  Pipeline: global-data-processor                                │
│                                                                 │
│  ┌─────────┐     ┌─────────────────────────────────┐           │
│  │ ingest  │────▶│     PARALLEL FEDERATION         │           │
│  │ (local) │     │  ┌───────┐ ┌───────┐ ┌───────┐ │           │
│  └─────────┘     │  │US-EAST│ │EU-WEST│ │AP-EAST│ │           │
│                  │  │process│ │process│ │process│ │           │
│                  │  └───┬───┘ └───┬───┘ └───┬───┘ │           │
│                  └──────┼─────────┼─────────┼─────┘           │
│                         └─────────┼─────────┘                  │
│                                   ▼                            │
│                            ┌───────────┐                       │
│                            │  aggregate │                       │
│                            └───────────┘                       │
└─────────────────────────────────────────────────────────────────┘
```

#### Federation Config
```json
{
  "stages": [{
    "id": "process-data",
    "component_type": "transformer",
    "federation": {
      "strategy": "parallel",
      "regions": ["us-east-1", "eu-west-1", "ap-northeast-1"],
      "data_locality": true,
      "aggregation": "merge"
    }
  }]
}
```

#### New Files
```
core/flowmason_core/federation/
├── __init__.py
├── coordinator.py        # Central coordination
├── remote_executor.py    # Cross-region execution
├── data_router.py        # Data routing
└── consensus.py          # Distributed state

studio/flowmason_studio/api/routes/federation.py
studio/flowmason_studio/services/federation_service.py
```

---

### 6.3 Mobile Companion App
**Effort:** High (60-80 hours) | **Priority:** 9 | **Status:** ✅ Complete

Monitor and trigger pipelines from mobile devices.

#### Features
- Pipeline monitoring dashboard
- Push notifications for completions/failures
- Quick trigger for favorite pipelines
- Execution history and logs
- Voice commands (Siri/Google Assistant)

#### New Repository: `flowmason-mobile/`
```
flowmason-mobile/
├── src/
│   ├── screens/
│   │   ├── Dashboard.tsx
│   │   ├── PipelineList.tsx
│   │   ├── PipelineDetail.tsx
│   │   └── Settings.tsx
│   ├── services/
│   │   ├── api.ts
│   │   └── notifications.ts
│   └── App.tsx
├── ios/
├── android/
└── package.json
```

---

## Implementation Phases

### Phase 1: Foundation
| Feature | Effort | Dependencies |
|---------|--------|--------------|
| Pipeline Inheritance & Composition | 40-60h | None |
| Visual Pipeline Diff & Merge | 50-70h | None |
| AI Co-pilot Integration | 60-80h | None |

### Phase 2: Enhancement
| Feature | Effort | Dependencies |
|---------|--------|--------------|
| Natural Language Triggers | 30-40h | AI Co-pilot |
| Visual Debugging (Animated) | 40-50h | Diff/Merge |
| Kubernetes Operator | 80-100h | None |

### Phase 3: Scale
| Feature | Effort | Dependencies |
|---------|--------|--------------|
| Edge Deployment | 60-80h | None |
| Federated Execution | 100-120h | Edge Deployment |
| Mobile Companion App | 60-80h | None |

---

## Effort Summary

| Feature | Effort (hours) | Phase |
|---------|---------------|-------|
| Pipeline Inheritance & Composition | 40-60 | 1 |
| Visual Pipeline Diff & Merge | 50-70 | 1 |
| AI Co-pilot Integration | 60-80 | 1 |
| Natural Language Triggers | 30-40 | 2 |
| Visual Debugging (Animated) | 40-50 | 2 |
| Kubernetes Operator | 80-100 | 2 |
| Edge Deployment | 60-80 | 3 |
| Federated Execution | 100-120 | 3 |
| Mobile Companion App | 60-80 | 3 |
| **Total** | **520-680** | |

---

## Critical Files to Modify

### Core Framework
- `core/flowmason_core/execution/dag_executor.py`
- `core/flowmason_core/config/types.py`
- `core/flowmason_core/registry/`

### Studio Backend
- `studio/flowmason_studio/api/app.py`
- `studio/flowmason_studio/services/`

### VSCode Extension
- `vscode-extension/src/editors/dagCanvasProvider.ts`
- `vscode-extension/src/debug/`
- `vscode-extension/package.json`

### New Packages (to create)
- `flowmason-operator/` - Kubernetes operator (Go)
- `flowmason-edge/` - Edge runtime (Python)
- `flowmason-mobile/` - Mobile app (React Native)


---

## 03-concepts/diff-merge.md

# Visual Pipeline Diff & Merge

FlowMason provides Git-style diff and merge capabilities for pipeline files, with both structural and visual representations.

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│  Pipeline Diff: main.pipeline.json                              │
├─────────────────────────────────────────────────────────────────┤
│  BASE:                                                          │
│  ┌─────────┐     ┌─────────┐     ┌─────────┐                   │
│  │ fetch   │────▶│ process │────▶│ output  │                   │
│  └─────────┘     └─────────┘     └─────────┘                   │
│                                                                 │
│  THEIRS:                                                        │
│  ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐   │
│  │ fetch   │────▶│ validate│────▶│ process │────▶│ output  │   │
│  └─────────┘     └─────────┘     └─────────┘     └─────────┘   │
│                  ▲ ADDED                                        │
├─────────────────────────────────────────────────────────────────┤
│  + Added stage: validate (schema_validate)                      │
│  ~ Modified: process.config.temperature: 0.7 → 0.9              │
│  - Removed: output.config.format                                │
└─────────────────────────────────────────────────────────────────┘
```

## Comparing Pipelines

### Python API

```python
from flowmason_core.diff import PipelineDiffer, DiffFormatter

# Create differ
differ = PipelineDiffer()

# Compare two pipelines
diff_result = differ.diff(pipeline_a, pipeline_b)

# Check what changed
print(f"Added stages: {diff_result.added_stages}")
print(f"Removed stages: {diff_result.removed_stages}")
print(f"Modified stages: {diff_result.modified_stages}")
print(f"Moved stages: {diff_result.moved_stages}")

# Format diff for display
formatter = DiffFormatter()
print(formatter.format_diff(diff_result))
```

### CLI

```bash
# Compare two pipeline files
fm diff pipeline-v1.json pipeline-v2.json

# Output as colored text
fm diff pipeline-v1.json pipeline-v2.json --format colored

# Output as markdown
fm diff pipeline-v1.json pipeline-v2.json --format markdown
```

## Diff Result Structure

The `DiffResult` contains:

| Property | Type | Description |
|----------|------|-------------|
| `added_stages` | `List[str]` | Stage IDs that exist only in the second pipeline |
| `removed_stages` | `List[str]` | Stage IDs that exist only in the first pipeline |
| `modified_stages` | `List[ModifiedStage]` | Stages with changed configurations |
| `moved_stages` | `List[MovedStage]` | Stages with changed dependencies |
| `config_changes` | `Dict` | Pipeline-level config changes |

## Three-Way Merge

For merging branches with a common ancestor, use the `ThreeWayMerger`.

### Python API

```python
from flowmason_core.diff import ThreeWayMerger

merger = ThreeWayMerger()

# Merge with base (ancestor), ours, and theirs
merge_result = merger.merge(
    base=ancestor_pipeline,
    ours=our_pipeline,
    theirs=their_pipeline
)

if merge_result.is_clean:
    # No conflicts, get merged pipeline
    merged_pipeline = merge_result.merged
else:
    # Handle conflicts
    for conflict in merge_result.conflicts:
        print(f"Conflict in stage: {conflict.stage_id}")
        print(f"  Ours: {conflict.ours}")
        print(f"  Theirs: {conflict.theirs}")
```

### CLI

```bash
# Three-way merge
fm merge base.json ours.json theirs.json --output merged.json

# With conflict markers (if conflicts exist)
fm merge base.json ours.json theirs.json --conflict-markers
```

## Conflict Resolution

When conflicts occur, FlowMason provides several resolution strategies:

```python
from flowmason_core.diff import ThreeWayMerger, ConflictResolution

merger = ThreeWayMerger()

# Auto-resolve with strategy
merge_result = merger.merge(
    base, ours, theirs,
    resolution_strategy=ConflictResolution.OURS  # or THEIRS
)

# Manual resolution
if not merge_result.is_clean:
    for conflict in merge_result.conflicts:
        # Resolve each conflict manually
        merger.resolve_conflict(
            conflict.stage_id,
            resolution=conflict.ours  # Choose which version to keep
        )
```

## Output Formats

### Text Format
```
Pipeline Diff: pipeline.json
=============================
+ Added: validate (schema_validate)
- Removed: legacy_transform
~ Modified: process
    config.temperature: 0.7 → 0.9
    config.model: gpt-4 → claude-3
```

### Colored Format
Uses ANSI colors for terminal display:
- Green: Added stages
- Red: Removed stages
- Yellow: Modified stages

### Markdown Format
```markdown
## Pipeline Diff

### Added Stages
- `validate` (schema_validate)

### Removed Stages
- `legacy_transform`

### Modified Stages
#### process
| Property | Before | After |
|----------|--------|-------|
| config.temperature | 0.7 | 0.9 |
```

## VSCode Integration

The VSCode extension provides visual diff capabilities:

1. **Side-by-side Diff**: View pipelines side by side with highlighting
2. **DAG Overlay**: See structural changes in the visual DAG
3. **Inline Changes**: View config changes inline
4. **Merge UI**: Interactive three-way merge interface

### Opening Diff View

```
Command Palette > FlowMason: Compare Pipelines
```

Or right-click on a pipeline file and select "Compare with..."

## Best Practices

1. **Review Before Merge**: Always review diff output before merging
2. **Use Semantic Commits**: Commit pipeline changes with meaningful messages
3. **Test After Merge**: Run pipeline tests after merging
4. **Resolve Conflicts Carefully**: Don't auto-resolve important conflicts


---

## 03-concepts/inheritance.md

# Pipeline Inheritance & Composition

Pipeline inheritance allows you to create reusable base pipelines that can be extended and customized by child pipelines. This promotes code reuse and standardization across your organization.

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│  Base Pipeline (abstract)                                       │
│  ┌─────────┐     ┌─────────┐     ┌─────────┐                   │
│  │validate │────▶│transform│────▶│ output  │                   │
│  │         │     │(abstract)│     │         │                   │
│  └─────────┘     └─────────┘     └─────────┘                   │
└─────────────────────────────────────────────────────────────────┘
                            │
                            │ extends
                            ▼
┌─────────────────────────────────────────────────────────────────┐
│  Customer ETL Pipeline                                          │
│  ┌─────────┐     ┌─────────┐     ┌─────────┐                   │
│  │validate │────▶│json_    │────▶│ output  │                   │
│  │(inherited)│   │transform│     │(inherited)│                  │
│  └─────────┘     └─────────┘     └─────────┘                   │
└─────────────────────────────────────────────────────────────────┘
```

## Creating a Base Pipeline

Base pipelines define the structure that child pipelines will inherit. Mark a pipeline as `abstract` if it shouldn't be executed directly.

```json
{
  "id": "base-etl",
  "name": "Base ETL Pipeline",
  "abstract": true,
  "stages": [
    {
      "id": "validate",
      "type": "schema_validate",
      "config": {
        "strict": true
      }
    },
    {
      "id": "transform",
      "type": "abstract"
    },
    {
      "id": "output",
      "type": "logger",
      "depends_on": ["transform"]
    }
  ]
}
```

## Extending a Pipeline

Use the `extends` field to inherit from a base pipeline and `overrides` to customize specific stages.

```json
{
  "id": "customer-etl",
  "name": "Customer ETL Pipeline",
  "extends": "base-etl",
  "overrides": {
    "transform": {
      "type": "json_transform",
      "config": {
        "mapping": {
          "customer_id": "{{input.id}}",
          "full_name": "{{input.first_name}} {{input.last_name}}"
        }
      }
    }
  }
}
```

## Python API

### InheritanceResolver

Resolves the complete pipeline configuration by merging parent and child configs.

```python
from flowmason_core.inheritance import InheritanceResolver

resolver = InheritanceResolver()

# Load pipeline with inheritance resolved
pipeline = resolver.resolve("customer-etl", pipeline_registry)

# Check inheritance chain
chain = resolver.get_inheritance_chain("customer-etl", pipeline_registry)
print(chain)  # ['base-etl', 'customer-etl']
```

### PipelineMerger

Merges parent and child pipeline configurations.

```python
from flowmason_core.inheritance import PipelineMerger

merger = PipelineMerger()

# Merge child overrides into parent
merged = merger.merge(parent_config, child_config)
```

### InheritanceValidator

Validates inheritance rules and detects issues.

```python
from flowmason_core.inheritance import InheritanceValidator

validator = InheritanceValidator()

# Validate inheritance configuration
result = validator.validate(pipeline_config, pipeline_registry)

if not result.is_valid:
    for error in result.errors:
        print(f"Error: {error}")
```

## Validation Rules

The inheritance system enforces several rules:

1. **No Circular Inheritance**: A pipeline cannot extend itself or create a cycle
2. **Abstract Stage Override**: Abstract stages must be overridden in child pipelines
3. **Type Compatibility**: Overridden stages must be compatible with the parent
4. **Dependency Preservation**: Stage dependencies must remain valid after inheritance

## CLI Commands

### Validate Inheritance

```bash
fm validate --check-inheritance customer-etl.pipeline.json
```

### Show Inheritance Chain

```bash
fm info --inheritance customer-etl.pipeline.json
```

## Best Practices

1. **Use Abstract Pipelines**: Mark base pipelines as `abstract` to prevent accidental execution
2. **Document Override Points**: Clearly document which stages are meant to be overridden
3. **Keep Inheritance Shallow**: Avoid deep inheritance chains (max 3 levels recommended)
4. **Version Base Pipelines**: Use semantic versioning for base pipelines

## Example: Multi-Environment ETL

```json
// base-etl.pipeline.json
{
  "id": "base-etl",
  "abstract": true,
  "stages": [
    { "id": "extract", "type": "abstract" },
    { "id": "validate", "type": "schema_validate" },
    { "id": "transform", "type": "abstract" },
    { "id": "load", "type": "abstract" }
  ]
}

// prod-etl.pipeline.json
{
  "id": "prod-etl",
  "extends": "base-etl",
  "overrides": {
    "extract": { "type": "http_request", "config": { "url": "https://api.prod.example.com" } },
    "transform": { "type": "json_transform", "config": { "mapping": {...} } },
    "load": { "type": "database_write", "config": { "connection": "prod-db" } }
  }
}

// dev-etl.pipeline.json
{
  "id": "dev-etl",
  "extends": "base-etl",
  "overrides": {
    "extract": { "type": "file_read", "config": { "path": "./test-data.json" } },
    "transform": { "type": "json_transform", "config": { "mapping": {...} } },
    "load": { "type": "logger", "config": { "level": "debug" } }
  }
}
```


---

## 03-concepts/testing.md

# Pipeline Testing

FlowMason provides a comprehensive testing framework for pipeline development, including mocking, snapshot testing, and LLM call recording.

## Overview

The testing module includes:
- **MockProvider**: Mock LLM providers for deterministic testing
- **ComponentMocker**: Mock individual components and stages
- **SnapshotManager**: Snapshot testing for pipeline outputs
- **LLMCallRecorder**: Record and replay LLM calls

## Quick Start

```python
from flowmason_core.testing import (
    MockProvider,
    MockContext,
    ComponentMocker,
    assert_snapshot,
)

# Create a mock provider with predetermined responses
provider = MockProvider(responses=[
    "First LLM response",
    "Second LLM response",
])

# Test with the mock provider
response = provider.call("What is AI?")
assert response.content == "First LLM response"
assert provider.call_count == 1
```

## Mock Provider

The `MockProvider` allows you to test pipelines without making actual LLM calls.

### Basic Usage

```python
from flowmason_core.testing import MockProvider, ProviderResponse

# Create with simple string responses
provider = MockProvider(responses=[
    "Hello, world!",
    "How can I help you?",
])

# Or with full ProviderResponse objects
provider = MockProvider(responses=[
    ProviderResponse(
        content="Hello, world!",
        model="gpt-4",
        usage={"input_tokens": 10, "output_tokens": 20},
        success=True,
    ),
])

# Use in your pipeline
result = provider.call("Say hello")
print(result.content)  # "Hello, world!"
```

### Tracking Calls

```python
provider = MockProvider(responses=["Response 1", "Response 2"])

# Make some calls
provider.call("First prompt")
provider.call("Second prompt", system="Be helpful")

# Check call history
print(provider.call_count)  # 2
print(provider.call_history[0]["prompt"])  # "First prompt"
print(provider.call_history[1]["system"])  # "Be helpful"

# Reset for next test
provider.reset()
```

## Component Mocking

The `ComponentMocker` allows you to mock specific components or stages.

### Mock by Component Type

```python
from flowmason_core.testing import ComponentMocker

mocker = ComponentMocker()

# Mock all generators
mocker.mock_component("generator", responses=[
    {"content": "Generated content 1"},
    {"content": "Generated content 2"},
])

# Mock with custom handler
mocker.mock_component(
    "filter",
    handler=lambda input: {"filtered": input.get("items", [])[:3]}
)

# Apply mocks during test
with mocker.apply():
    result = await run_pipeline(...)

# Check calls
print(mocker.get_component_calls("generator"))
```

### Mock by Stage ID

```python
mocker = ComponentMocker()

# Mock specific stages
stage_mock = mocker.mock_stage(
    "extract-data",
    responses=[{"data": [1, 2, 3]}],
)

stage_mock = mocker.mock_stage(
    "validate-data",
    should_fail=True,
    error_message="Validation failed",
)

# Check stage calls
print(stage_mock.call_count)
print(stage_mock.call_history)
```

## Snapshot Testing

Snapshot testing captures pipeline outputs and compares them against saved baselines.

### Basic Snapshot Testing

```python
from flowmason_core.testing import assert_snapshot

# Run pipeline and capture output
result = await run_pipeline("my-pipeline", input_data)

# Assert against snapshot
assert_snapshot(
    name="my_pipeline_output",
    actual=result,
    snapshot_dir="tests/snapshots",
)
```

### Using SnapshotManager

```python
from flowmason_core.testing import SnapshotManager, format_diff_report

snapshots = SnapshotManager("tests/snapshots")

# Save initial snapshot
snapshots.save("pipeline_v1", result, metadata={
    "pipeline_version": "1.0.0",
    "test_date": "2024-01-15",
})

# Compare new output
comparison = snapshots.compare("pipeline_v1", new_result)

if not comparison.matches:
    print(format_diff_report(comparison))

    # Optionally update if changes are expected
    # snapshots.update("pipeline_v1", new_result)
```

### Ignoring Dynamic Fields

```python
# Ignore timestamps and IDs that change between runs
snapshots = SnapshotManager(
    "tests/snapshots",
    ignore_keys=[
        "timestamp",
        "run_id",
        "created_at",
        "duration_ms",
    ],
)
```

### Snapshot All Stages

```python
from flowmason_core.testing import snapshot_stage_outputs

# Snapshot each stage output separately
results = snapshot_stage_outputs(
    stage_results=pipeline_result["stage_results"],
    snapshot_dir="tests/snapshots/stages",
    prefix="test_case_1_",
)

# Check which stages match
for stage_id, result in results.items():
    if not result.matches:
        print(f"Stage {stage_id} output changed")
```

## LLM Call Recording

Record actual LLM calls for deterministic replay in tests.

### Recording Calls

```python
from flowmason_core.testing import LLMCallRecorder

recorder = LLMCallRecorder()

# Record calls during execution
with recorder.record():
    result = await run_pipeline(...)

# Save recorded calls
recorder.save("tests/fixtures/llm_calls.json")
print(f"Recorded {len(recorder.calls)} LLM calls")
```

### Replaying Calls

```python
recorder = LLMCallRecorder()

# Replay recorded calls
with recorder.replay("tests/fixtures/llm_calls.json"):
    result = await run_pipeline(...)
    # LLM calls return recorded responses instead of making real calls
```

## Mock Context

Use `MockContext` when testing components that require execution context.

```python
from flowmason_core.testing import MockContext, MockProvider

context = MockContext(
    run_id="test-run-001",
    pipeline_id="test-pipeline",
    pipeline_input={"query": "test input"},
    variables={"api_key": "test-key"},
    providers={"default": MockProvider(responses=["Test response"])},
)

# Use context in component tests
result = await my_component.execute(input_data, context=context)
```

## Creating Test Executors

For testing pipeline execution logic, create mock executors:

```python
from flowmason_core.testing import create_mock_executor

# Define expected stage outputs
mock_executor = create_mock_executor({
    "extract": {"data": [1, 2, 3]},
    "transform": {"result": [2, 4, 6]},
    "load": {"status": "success"},
})

# Use in pipeline tests
result = await run_with_executor(pipeline, mock_executor)

# Check what was called
print(mock_executor.call_history)
```

## Best Practices

### 1. Use Deterministic Tests

```python
# Good: Deterministic mock responses
provider = MockProvider(responses=["Fixed response"])

# Avoid: Random or time-dependent tests
```

### 2. Isolate LLM Calls

```python
# Mock LLM calls for fast, reliable tests
mocker = ComponentMocker()
mocker.mock_component("generator", responses=["Mocked LLM output"])
```

### 3. Update Snapshots Intentionally

```python
# Only update when changes are expected
if os.environ.get("UPDATE_SNAPSHOTS"):
    snapshots.update("test_name", result)
else:
    comparison = snapshots.compare("test_name", result)
    assert comparison.matches
```

### 4. Record Once, Replay Often

```python
# Record LLM calls in integration tests
if os.environ.get("RECORD_LLM_CALLS"):
    with recorder.record():
        result = await run_pipeline(...)
    recorder.save("fixtures/llm_calls.json")
else:
    # Replay in unit tests
    with recorder.replay("fixtures/llm_calls.json"):
        result = await run_pipeline(...)
```

### 5. Test Error Handling

```python
# Test failure scenarios
mocker.mock_stage(
    "validate",
    should_fail=True,
    error_message="Invalid input format",
)

with pytest.raises(PipelineError) as exc:
    await run_pipeline(...)

assert "Invalid input format" in str(exc.value)
```

## Complete Test Example

```python
import pytest
from flowmason_core.testing import (
    MockProvider,
    MockContext,
    ComponentMocker,
    SnapshotManager,
    assert_snapshot,
)

@pytest.fixture
def mock_provider():
    return MockProvider(responses=[
        "Summary of the input text",
        "Key points: 1, 2, 3",
    ])

@pytest.fixture
def mocker():
    m = ComponentMocker()
    m.mock_component("generator", responses=[
        {"summary": "Test summary"},
    ])
    return m

@pytest.fixture
def snapshots():
    return SnapshotManager("tests/snapshots")

async def test_pipeline_output(mock_provider, mocker, snapshots):
    """Test pipeline produces expected output."""
    context = MockContext(
        providers={"default": mock_provider},
    )

    with mocker.apply():
        result = await run_pipeline(
            "summarizer",
            input_data={"text": "Long document..."},
            context=context,
        )

    # Assert structure
    assert result["success"] is True
    assert "summary" in result["output"]

    # Assert against snapshot
    assert_snapshot("summarizer_output", result["output"])

    # Verify LLM was called correctly
    assert mock_provider.call_count == 1
    assert "Long document" in mock_provider.call_history[0]["prompt"]

async def test_pipeline_handles_errors(mocker):
    """Test pipeline error handling."""
    mocker.mock_stage("validate", should_fail=True)

    with pytest.raises(StageError) as exc:
        await run_pipeline("validator", {"data": "test"})

    assert "Mocked error" in str(exc.value)
```


---

## 05-sdk/python-sdk.md

# Python SDK

FlowMason provides a Python SDK for programmatic pipeline creation and execution.

## Installation

```bash
pip install flowmason
```

## Quick Start

```python
import asyncio
from flowmason_core import FlowMason

async def main():
    # Initialize with API keys from environment
    fm = FlowMason()

    # Run a pipeline from file
    result = await fm.run_pipeline_file(
        "./pipelines/my-pipeline.pipeline.json",
        {"query": "Hello, world!"}
    )

    print(result.output)

asyncio.run(main())
```

## Initialization

### Basic Setup

```python
from flowmason_core import FlowMason

# Auto-loads API keys from environment variables
fm = FlowMason()

# Or provide explicitly
fm = FlowMason(
    providers={
        "anthropic": "sk-ant-...",
        "openai": "sk-..."
    },
    default_provider="anthropic"
)
```

### Environment Variables

The SDK automatically loads from these environment variables:

| Variable | Provider |
|----------|----------|
| `ANTHROPIC_API_KEY` | Anthropic (Claude) |
| `OPENAI_API_KEY` | OpenAI (GPT) |
| `GOOGLE_API_KEY` | Google (Gemini) |
| `GROQ_API_KEY` | Groq |

### Async Context Manager

```python
async with FlowMason() as fm:
    result = await fm.run_pipeline_file("./pipeline.json", {})
```

## Running Pipelines

### From File

```python
# Load and run in one step
result = await fm.run_pipeline_file(
    "./pipelines/my-pipeline.pipeline.json",
    {"topic": "AI Safety"}
)

# Or load first, run later
pipeline = fm.load_pipeline("./pipelines/my-pipeline.pipeline.json")
result = await pipeline.run({"topic": "AI Safety"})
```

### From Studio

Run pipelines stored in FlowMason Studio:

```python
result = await fm.run_from_studio(
    pipeline_id="abc123",
    input={"query": "Hello"},
    studio_url="http://localhost:8999"
)
```

### Inline Definition

Define pipelines programmatically:

```python
pipeline = fm.pipeline(
    name="Content Generator",
    stages=[
        fm.stage("generator",
            id="generate",
            config={"prompt": "Write about {{topic}}"}
        ),
        fm.stage("critic",
            id="review",
            config={"focus": "clarity"},
            depends_on=["generate"]
        ),
    ]
)

result = await pipeline.run({"topic": "Machine Learning"})
```

## Progress Callbacks

Track execution progress with async callbacks:

```python
async def on_start(stage_id, data):
    print(f"Starting: {stage_id}")

async def on_complete(stage_id, output):
    print(f"Completed: {stage_id}")
    print(f"Output: {output}")

async def on_error(stage_id, error):
    print(f"Error in {stage_id}: {error}")

result = await pipeline.run(
    {"topic": "AI"},
    on_stage_start=on_start,
    on_stage_complete=on_complete,
    on_stage_error=on_error
)
```

## Pipeline Result

```python
result = await pipeline.run({"topic": "AI"})

# Check success
if result.success:
    print(result.output)
else:
    print(f"Error: {result.error}")

# Access stage results
for stage_id, stage_result in result.stage_results.items():
    print(f"{stage_id}: {stage_result.output}")

# Usage metrics
print(f"Input tokens: {result.usage.input_tokens}")
print(f"Output tokens: {result.usage.output_tokens}")
print(f"Total cost: ${result.usage.total_cost_usd:.4f}")
```

## Components

### Loading Packages

```python
# Load all packages from a directory
fm.load_packages("./packages")

# Load a single package
fm.load_package("./packages/my-package.fmpkg")
```

### Listing Components

```python
# All components
components = fm.list_components()

# By category
ai_components = fm.list_components(category="ai")
```

### Component Info

```python
info = fm.get_component_info("generator")
print(f"Name: {info['name']}")
print(f"Description: {info['description']}")
print(f"Requires LLM: {info['requires_llm']}")
```

### Running Components Directly

```python
result = await fm.run_component(
    "generator",
    {"prompt": "Write a haiku about coding"}
)
print(result.output.content)
```

### Custom Components

Register custom components at runtime:

```python
from flowmason_core import node, NodeInput, NodeOutput, Field

@node(
    name="uppercase",
    description="Convert text to uppercase"
)
class UppercaseNode:
    class Input(NodeInput):
        text: str = Field(description="Text to convert")

    class Output(NodeOutput):
        result: str = Field(description="Uppercase text")

    async def execute(self, input, context):
        return self.Output(result=input.text.upper())

# Register with FlowMason
fm.register_component(UppercaseNode)

# Use in pipelines
result = await fm.run_component("uppercase", {"text": "hello"})
print(result.output.result)  # "HELLO"
```

## Validation

Validate pipelines before running:

```python
pipeline = fm.load_pipeline("./my-pipeline.pipeline.json")
errors = pipeline.validate()

if errors:
    for error in errors:
        print(f"Validation error: {error}")
else:
    result = await pipeline.run({})
```

## Trace IDs

For observability, pass trace IDs:

```python
import uuid

trace_id = str(uuid.uuid4())
result = await pipeline.run(
    {"query": "Hello"},
    trace_id=trace_id
)

# Use trace_id to correlate logs, metrics, etc.
```

## Error Handling

```python
try:
    result = await fm.run_pipeline_file("./pipeline.json", {})

    if not result.success:
        print(f"Pipeline failed: {result.error}")

except FileNotFoundError:
    print("Pipeline file not found")
except Exception as e:
    print(f"Unexpected error: {e}")
```

## Provider Information

```python
# Configured providers (with API keys)
print(fm.configured_providers)  # ['anthropic', 'openai']

# All available providers
print(fm.available_providers)  # ['anthropic', 'openai', 'google', 'groq']
```

## Complete Example

```python
import asyncio
from flowmason_core import FlowMason, node, NodeInput, NodeOutput, Field

@node(name="formatter", category="utility")
class FormatterNode:
    class Input(NodeInput):
        text: str
        format: str = "uppercase"

    class Output(NodeOutput):
        result: str

    async def execute(self, input, context):
        if input.format == "uppercase":
            return self.Output(result=input.text.upper())
        elif input.format == "lowercase":
            return self.Output(result=input.text.lower())
        return self.Output(result=input.text)

async def main():
    async with FlowMason() as fm:
        # Register custom component
        fm.register_component(FormatterNode)

        # Define pipeline
        pipeline = fm.pipeline(
            name="Text Processor",
            stages=[
                fm.stage("generator",
                    id="generate",
                    config={"prompt": "Write a short greeting"}
                ),
                fm.stage("formatter",
                    id="format",
                    config={
                        "text": "{{stages.generate.output.content}}",
                        "format": "uppercase"
                    },
                    depends_on=["generate"]
                ),
            ]
        )

        # Run with progress tracking
        async def log_progress(stage_id, output):
            print(f"[{stage_id}] Done")

        result = await pipeline.run(
            {},
            on_stage_complete=log_progress
        )

        if result.success:
            print(f"\nFinal output: {result.output}")
        else:
            print(f"\nError: {result.error}")

if __name__ == "__main__":
    asyncio.run(main())
```

## API Reference

### FlowMason Class

| Method | Description |
|--------|-------------|
| `load_pipeline(path)` | Load pipeline from file |
| `run_pipeline_file(path, input)` | Load and run pipeline |
| `run_from_studio(id, input)` | Run pipeline from Studio |
| `pipeline(name, stages)` | Create inline pipeline |
| `stage(type, config)` | Create stage definition |
| `run_component(type, config)` | Run single component |
| `load_packages(path)` | Load component packages |
| `register_component(cls)` | Register custom component |
| `list_components(category)` | List available components |
| `get_component_info(type)` | Get component metadata |

### Pipeline Class

| Method | Description |
|--------|-------------|
| `run(input, callbacks)` | Execute the pipeline |
| `validate()` | Validate configuration |

### PipelineResult

| Property | Type | Description |
|----------|------|-------------|
| `success` | bool | Whether pipeline succeeded |
| `output` | dict | Final stage output |
| `stage_results` | dict | All stage results |
| `usage` | UsageMetrics | Token/cost metrics |
| `error` | str | Error message if failed |
| `final_output` | any | Convenience accessor |


---

## 05-sdk/react-hooks-sdk.md

# React Hooks SDK

FlowMason provides a React SDK with hooks for seamless pipeline integration in React applications.

## Installation

```bash
npm install @flowmason/react
```

## Quick Start

```tsx
import { FlowMasonProvider, usePipeline } from '@flowmason/react';

function App() {
  return (
    <FlowMasonProvider config={{ studioUrl: 'http://localhost:8999/api/v1' }}>
      <ContentGenerator />
    </FlowMasonProvider>
  );
}

function ContentGenerator() {
  const { run, result, isRunning, error } = usePipeline('content-generator');

  const handleGenerate = async () => {
    await run({ topic: 'AI Safety', style: 'professional' });
  };

  return (
    <div>
      <button onClick={handleGenerate} disabled={isRunning}>
        {isRunning ? 'Generating...' : 'Generate Content'}
      </button>

      {error && <div className="error">{error}</div>}

      {result?.success && (
        <article>{result.output.content}</article>
      )}
    </div>
  );
}
```

## Provider Setup

### Basic Configuration

```tsx
import { FlowMasonProvider } from '@flowmason/react';

function App() {
  return (
    <FlowMasonProvider
      config={{
        studioUrl: 'http://localhost:8999/api/v1',
        apiKey: process.env.REACT_APP_FLOWMASON_API_KEY,
        orgId: 'my-org',
        timeout: 300000, // 5 minutes
      }}
    >
      <YourApp />
    </FlowMasonProvider>
  );
}
```

### With Custom Client

```tsx
import { FlowMasonProvider, FlowMasonClient } from '@flowmason/react';

const client = new FlowMasonClient({
  studioUrl: 'https://studio.example.com/api/v1',
  apiKey: 'sk-...',
});

function App() {
  return (
    <FlowMasonProvider client={client}>
      <YourApp />
    </FlowMasonProvider>
  );
}
```

## Hooks Reference

### usePipeline

Run a pipeline by ID with full state management.

```tsx
function PipelineRunner() {
  const {
    run,           // Execute the pipeline
    result,        // Latest result
    status,        // 'idle' | 'running' | 'success' | 'error'
    error,         // Error message if failed
    isLoading,     // Initial loading state
    isRunning,     // Currently executing
    isSuccess,     // Completed successfully
    isError,       // Failed with error
    progress,      // Execution progress
    cancel,        // Cancel execution
    reset,         // Reset to initial state
  } = usePipeline('pipeline-id');

  const handleRun = async () => {
    try {
      const result = await run(
        { query: 'Hello' },
        { traceId: 'trace-123' }
      );
      console.log('Output:', result.output);
    } catch (err) {
      console.error('Failed:', err);
    }
  };

  return (
    <div>
      <button onClick={handleRun} disabled={isRunning}>
        Run Pipeline
      </button>

      {progress && (
        <div>
          Stage: {progress.currentStageName}
          Progress: {progress.percentComplete}%
        </div>
      )}

      {isSuccess && <pre>{JSON.stringify(result?.output, null, 2)}</pre>}
      {isError && <div className="error">{error}</div>}
    </div>
  );
}
```

### usePipelineByName

Run a pipeline by name with optional version.

```tsx
function VersionedPipeline() {
  const { run, result, isRunning } = usePipelineByName(
    'content-generator',
    '2.0.0' // Optional version
  );

  const handleRun = async () => {
    await run({ topic: 'Machine Learning' });
  };

  return (
    <button onClick={handleRun} disabled={isRunning}>
      Generate with v2.0.0
    </button>
  );
}
```

### usePipelines

List and filter pipelines.

```tsx
function PipelineList() {
  const { pipelines, isLoading, error, refresh } = usePipelines({
    status: 'published',
    category: 'content',
    autoFetch: true,
  });

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;

  return (
    <div>
      <button onClick={refresh}>Refresh</button>
      <ul>
        {pipelines.map(p => (
          <li key={p.id}>{p.name} - v{p.version}</li>
        ))}
      </ul>
    </div>
  );
}
```

### usePipelineDetails

Get detailed information about a pipeline.

```tsx
function PipelineDetails({ id }: { id: string }) {
  const { pipeline, isLoading, error } = usePipelineDetails(id);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!pipeline) return null;

  return (
    <div>
      <h2>{pipeline.name}</h2>
      <p>{pipeline.description}</p>
      <h3>Stages ({pipeline.stages.length})</h3>
      <ul>
        {pipeline.stages.map(stage => (
          <li key={stage.id}>
            {stage.name || stage.id} ({stage.componentType})
          </li>
        ))}
      </ul>
    </div>
  );
}
```

### useComponents

List and filter available components.

```tsx
function ComponentLibrary() {
  const {
    components,
    isLoading,
    filterByCategory,
    filterByKind,
    refresh,
  } = useComponents();

  const aiNodes = filterByKind('node');
  const utilityOps = filterByCategory('utility');

  return (
    <div>
      <h2>AI Nodes ({aiNodes.length})</h2>
      <ul>
        {aiNodes.map(c => (
          <li key={c.componentType}>
            <strong>{c.name}</strong>: {c.description}
          </li>
        ))}
      </ul>

      <h2>Utility Operators ({utilityOps.length})</h2>
      <ul>
        {utilityOps.map(c => (
          <li key={c.componentType}>{c.name}</li>
        ))}
      </ul>
    </div>
  );
}
```

### useRunHistory

Access pipeline execution history.

```tsx
function RunHistory({ pipelineId }: { pipelineId: string }) {
  const { runs, isLoading, getRun, refresh } = useRunHistory({
    pipelineId,
    limit: 20,
  });

  const viewDetails = async (runId: string) => {
    const run = await getRun(runId);
    console.log('Run details:', run);
  };

  return (
    <table>
      <thead>
        <tr>
          <th>Run ID</th>
          <th>Status</th>
          <th>Duration</th>
          <th>Actions</th>
        </tr>
      </thead>
      <tbody>
        {runs.map(run => (
          <tr key={run.runId}>
            <td>{run.runId}</td>
            <td>{run.status}</td>
            <td>{run.durationMs}ms</td>
            <td>
              <button onClick={() => viewDetails(run.runId)}>
                View
              </button>
            </td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}
```

### useStreamingPipeline

Real-time stage updates during execution.

```tsx
function StreamingExecution() {
  const { run, result, stages, progress, isRunning } = useStreamingPipeline('pipeline-id');

  return (
    <div>
      <button onClick={() => run({ input: 'data' })} disabled={isRunning}>
        Run with Streaming
      </button>

      <div className="stages">
        {Object.entries(stages).map(([stageId, status]) => (
          <div key={stageId} className={`stage stage-${status}`}>
            {stageId}: {status}
          </div>
        ))}
      </div>

      {progress && (
        <progress value={progress.percentComplete} max={100} />
      )}
    </div>
  );
}
```

## Direct Client Access

For advanced use cases, access the client directly:

```tsx
import { useFlowMasonClient } from '@flowmason/react';

function AdvancedComponent() {
  const client = useFlowMasonClient();

  const handleBatchRun = async () => {
    const pipelines = ['pipeline-1', 'pipeline-2', 'pipeline-3'];

    const results = await Promise.all(
      pipelines.map(id => client.runPipeline(id, { query: 'test' }))
    );

    console.log('Batch results:', results);
  };

  return <button onClick={handleBatchRun}>Run Batch</button>;
}
```

## TypeScript Types

All types are exported for TypeScript users:

```tsx
import type {
  FlowMasonConfig,
  PipelineInput,
  PipelineResult,
  Pipeline,
  PipelineStage,
  Component,
  StageResult,
  UsageMetrics,
  RunOptions,
  PipelineProgress,
  PipelineStatus,
} from '@flowmason/react';
```

## Error Handling

```tsx
function RobustPipeline() {
  const { run, result, error, isError, reset } = usePipeline('pipeline-id');

  const handleRun = async () => {
    try {
      const result = await run({ input: 'data' });

      if (!result.success) {
        console.error('Pipeline failed:', result.error);
        // Handle pipeline-level errors
      }
    } catch (err) {
      // Handle network/client errors
      console.error('Request failed:', err);
    }
  };

  return (
    <div>
      <button onClick={handleRun}>Run</button>

      {isError && (
        <div className="error">
          <p>{error}</p>
          <button onClick={reset}>Try Again</button>
        </div>
      )}
    </div>
  );
}
```

## Best Practices

### 1. Use Provider at App Root

```tsx
// ✅ Good - Provider at root
function App() {
  return (
    <FlowMasonProvider config={config}>
      <Router>
        <Routes />
      </Router>
    </FlowMasonProvider>
  );
}
```

### 2. Handle Loading States

```tsx
// ✅ Good - Complete state handling
function Pipeline() {
  const { run, isRunning, isSuccess, isError, result, error } = usePipeline('id');

  if (isRunning) return <Spinner />;
  if (isError) return <ErrorMessage message={error} />;
  if (isSuccess) return <Result data={result} />;

  return <button onClick={() => run({})}>Start</button>;
}
```

### 3. Cancel on Unmount

The hooks automatically clean up, but for manual operations:

```tsx
function CancellablePipeline() {
  const { run, cancel, isRunning } = usePipeline('id');

  useEffect(() => {
    return () => {
      if (isRunning) cancel();
    };
  }, [isRunning, cancel]);

  return <button onClick={() => run({})}>Run</button>;
}
```

### 4. Use Trace IDs for Debugging

```tsx
function TrackedPipeline() {
  const { run } = usePipeline('id');

  const handleRun = async () => {
    const traceId = `web-${Date.now()}`;
    await run({ input: 'data' }, { traceId });
    console.log('Trace ID for debugging:', traceId);
  };

  return <button onClick={handleRun}>Run with Trace</button>;
}
```


---

## 05-sdk/typescript-sdk.md

# TypeScript SDK

FlowMason provides a TypeScript/JavaScript SDK for programmatic pipeline execution in Node.js and browser environments.

## Installation

```bash
npm install @flowmason/sdk
```

## Quick Start

```typescript
import { FlowMason } from '@flowmason/sdk';

const fm = new FlowMason({
  studioUrl: 'http://localhost:8999/api/v1',
  apiKey: process.env.FLOWMASON_API_KEY,
});

// Run a pipeline
const result = await fm.run('pipeline-id', {
  query: 'Hello, world!',
});

console.log(result.output);
```

## Configuration

### Options

```typescript
const fm = new FlowMason({
  // Studio API URL (default: http://localhost:8999/api/v1)
  studioUrl: 'https://studio.example.com/api/v1',

  // API key for authentication
  apiKey: 'sk-...',

  // Organization ID for multi-tenant setups
  orgId: 'org-123',

  // Default timeout in milliseconds (default: 300000)
  timeout: 60000,

  // Custom headers for all requests
  headers: {
    'X-Custom-Header': 'value',
  },

  // Custom fetch implementation (for special environments)
  fetch: customFetch,
});
```

### Environment Variables

The SDK automatically reads these environment variables:

| Variable | Description |
|----------|-------------|
| `FLOWMASON_API_KEY` | API key for authentication |
| `FLOWMASON_ORG_ID` | Organization ID |

## Running Pipelines

### Basic Execution

```typescript
const result = await fm.run('pipeline-id', {
  query: 'Generate content about AI',
  options: { temperature: 0.7 },
});

if (result.success) {
  console.log('Output:', result.output);
  console.log('Tokens used:', result.usage?.totalTokens);
  console.log('Cost:', result.usage?.totalCostUsd);
} else {
  console.error('Failed:', result.error);
}
```

### Run by Name

```typescript
// Latest version
const result = await fm.runByName('content-generator', { topic: 'AI' });

// Specific version
const result = await fm.runByName('content-generator@2.0.0', { topic: 'AI' });
```

### Run Options

```typescript
const result = await fm.run('pipeline-id', { input: 'data' }, {
  // Trace ID for observability
  traceId: 'trace-123',

  // Override timeout
  timeout: 120000,

  // Callback URL for completion notification
  callbackUrl: 'https://myapp.com/webhook/flowmason',

  // Run asynchronously (returns immediately with run ID)
  async: true,

  // Output routing configuration
  outputConfig: {
    destinations: [
      {
        type: 'webhook',
        config: { url: 'https://myapp.com/data' },
        onSuccess: true,
      },
    ],
  },
});
```

### Streaming Execution

Get real-time updates during pipeline execution:

```typescript
const result = await fm.runWithStream(
  'pipeline-id',
  { input: 'data' },
  {
    onStageStart: (stage) => {
      console.log(`Starting stage: ${stage.stageName || stage.stageId}`);
    },

    onStageComplete: (stage) => {
      console.log(`Completed: ${stage.stageId}`);
      console.log(`Duration: ${stage.durationMs}ms`);
    },

    onStageError: (stage) => {
      console.error(`Stage failed: ${stage.stageId}`);
      console.error(`Error: ${stage.error}`);
    },

    onProgress: (progress) => {
      console.log(`Progress: ${progress.percentComplete}%`);
      console.log(`Current: ${progress.currentStage}`);
    },

    onComplete: (result) => {
      console.log('Pipeline complete!');
      console.log('Output:', result.output);
    },

    onError: (error) => {
      console.error('Pipeline failed:', error.message);
    },
  }
);
```

### Async Execution with Polling

```typescript
// Start async run
const initialResult = await fm.run(
  'pipeline-id',
  { input: 'data' },
  { async: true }
);

console.log('Started run:', initialResult.runId);

// Poll for completion
const finalResult = await fm.waitForCompletion(initialResult.runId, {
  pollInterval: 2000,  // Check every 2 seconds
  timeout: 300000,     // 5 minute timeout
});

console.log('Completed:', finalResult.output);
```

### Cancel Execution

```typescript
// Cancel by run ID
await fm.cancelRun('run-id');

// Cancel current request
fm.cancel();
```

## Pipeline Management

### List Pipelines

```typescript
const { items, total, hasMore } = await fm.listPipelines({
  status: 'published',
  category: 'content',
  search: 'generator',
  limit: 20,
  offset: 0,
});

for (const pipeline of items) {
  console.log(`${pipeline.name} v${pipeline.version} - ${pipeline.status}`);
}
```

### Get Pipeline Details

```typescript
const pipeline = await fm.getPipeline('pipeline-id');

console.log('Name:', pipeline.name);
console.log('Description:', pipeline.description);
console.log('Stages:', pipeline.stages.length);
console.log('Input Schema:', JSON.stringify(pipeline.inputSchema, null, 2));
```

### Validate Pipeline

```typescript
const { valid, errors } = await fm.validatePipeline('pipeline-id', {
  query: 'test input',
});

if (!valid) {
  console.error('Validation errors:');
  for (const error of errors) {
    console.error(`  - ${error}`);
  }
}
```

## Run History

### List Runs

```typescript
const { items: runs } = await fm.listRuns({
  pipelineId: 'pipeline-id',
  status: 'completed',
  startDate: '2024-01-01',
  endDate: '2024-12-31',
  limit: 100,
});

for (const run of runs) {
  console.log(`${run.runId}: ${run.status} (${run.durationMs}ms)`);
}
```

### Get Run Details

```typescript
const run = await fm.getRun('run-id');

console.log('Status:', run.status);
console.log('Success:', run.success);
console.log('Output:', run.output);
console.log('Duration:', run.durationMs, 'ms');

// Stage results
for (const [stageId, stage] of Object.entries(run.stageResults)) {
  console.log(`  ${stageId}: ${stage.status}`);
}

// Usage metrics
if (run.usage) {
  console.log('Tokens:', run.usage.totalTokens);
  console.log('Cost: $', run.usage.totalCostUsd.toFixed(4));
}
```

### Get Run Logs

```typescript
const logs = await fm.getRunLogs('run-id');

for (const log of logs) {
  console.log(`[${log.timestamp}] ${log.level}: ${log.message}`);
}
```

## Component Registry

### List Components

```typescript
const { items: components } = await fm.listComponents({
  category: 'ai',
  kind: 'node',
});

for (const comp of components) {
  console.log(`${comp.componentType} (${comp.componentKind})`);
  console.log(`  ${comp.description}`);
  console.log(`  Requires LLM: ${comp.requiresLlm}`);
}
```

### Get Component Details

```typescript
const component = await fm.getComponent('generator');

console.log('Name:', component.name);
console.log('Category:', component.category);
console.log('Version:', component.version);
console.log('Input Schema:', component.inputSchema);
console.log('Output Schema:', component.outputSchema);
```

### List Categories

```typescript
const categories = await fm.listCategories();
console.log('Categories:', categories);
// ['ai', 'utility', 'control_flow', 'integration']
```

## Error Handling

```typescript
import { FlowMason, FlowMasonError } from '@flowmason/sdk';

try {
  const result = await fm.run('pipeline-id', { input: 'data' });
} catch (error) {
  if (error instanceof FlowMasonError) {
    console.error('FlowMason Error');
    console.error('  Message:', error.message);
    console.error('  Code:', error.code);
    console.error('  Status:', error.status);
    console.error('  Details:', error.details);

    switch (error.code) {
      case 'PIPELINE_NOT_FOUND':
        // Handle missing pipeline
        break;
      case 'VALIDATION_ERROR':
        // Handle invalid input
        break;
      case 'TIMEOUT':
        // Handle timeout
        break;
      case 'NETWORK_ERROR':
        // Handle network issues
        break;
    }
  } else {
    throw error;
  }
}
```

## TypeScript Types

Full TypeScript support with exported types:

```typescript
import type {
  FlowMasonConfig,
  Pipeline,
  PipelineResult,
  PipelineStage,
  PipelineStatus,
  Component,
  StageResult,
  StageStatus,
  UsageMetrics,
  RunOptions,
  RunStatus,
  StreamCallbacks,
  PaginatedResponse,
} from '@flowmason/sdk';

// Use in your code
function handleResult(result: PipelineResult) {
  if (result.success) {
    processOutput(result.output);
  }
}
```

## Advanced Usage

### Custom HTTP Client

```typescript
import { FlowMason } from '@flowmason/sdk';

// Use custom fetch (e.g., with retry logic)
const fm = new FlowMason({
  fetch: async (url, options) => {
    let lastError;
    for (let i = 0; i < 3; i++) {
      try {
        return await fetch(url, options);
      } catch (error) {
        lastError = error;
        await new Promise(r => setTimeout(r, 1000 * (i + 1)));
      }
    }
    throw lastError;
  },
});
```

### Batch Execution

```typescript
const pipelineIds = ['pipeline-1', 'pipeline-2', 'pipeline-3'];
const input = { query: 'Hello' };

const results = await Promise.all(
  pipelineIds.map(id => fm.run(id, input))
);

for (const result of results) {
  console.log(`${result.pipelineId}: ${result.success ? 'OK' : 'FAIL'}`);
}
```

### Rate Limiting

```typescript
import pLimit from 'p-limit';

const limit = pLimit(5); // Max 5 concurrent requests

const tasks = pipelines.map(id =>
  limit(() => fm.run(id, { input: 'data' }))
);

const results = await Promise.all(tasks);
```

## Health Check

```typescript
const health = await fm.health();
console.log('Status:', health.status);
console.log('Version:', health.version);

const info = await fm.info();
console.log('Server info:', info);
```


---

## 05-security/pipeline-permissions.md

# Pipeline-Level Permissions

FlowMason provides fine-grained access control for pipelines, allowing you to control who can view, run, edit, and manage your workflows.

## Overview

The permission system supports:
- **Permission Levels**: VIEW, RUN, EDIT, ADMIN with hierarchical inheritance
- **Visibility Settings**: Private, Organization, Public
- **Principal Types**: Users, Organizations, Teams, API Keys
- **Folder Inheritance**: Pipelines can inherit permissions from parent folders
- **Expiring Grants**: Time-limited access for temporary collaborations

## Permission Levels

| Level | Capabilities |
|-------|-------------|
| `view` | View pipeline definition and execution history |
| `run` | Execute pipeline (includes view) |
| `edit` | Modify pipeline definition (includes run) |
| `admin` | Full control including permission management |

Higher permission levels include all capabilities of lower levels.

## Visibility Settings

| Visibility | Description |
|------------|-------------|
| `private` | Only owner and explicit grants can access |
| `org` | All organization members can view |
| `public` | All authenticated users can view |

## API Reference

### Get Pipeline Permissions

```http
GET /api/v1/permissions/{pipeline_id}
```

Returns the full permission configuration for a pipeline.

**Response:**
```json
{
  "pipeline_id": "pipe_abc123",
  "owner_id": "user_xyz",
  "visibility": "private",
  "inherit_from_folder": true,
  "folder_id": "folder_001",
  "grants": [
    {
      "id": "grant_001",
      "principal_type": "user",
      "principal_id": "user_123",
      "level": "edit",
      "granted_by": "user_xyz",
      "granted_at": "2024-01-15T10:30:00Z"
    }
  ]
}
```

### Create Pipeline Permissions

```http
POST /api/v1/permissions/{pipeline_id}
```

Creates initial permissions for a new pipeline. The current user becomes the owner.

**Query Parameters:**
- `visibility` (optional): Initial visibility setting
- `folder_id` (optional): Parent folder for inheritance

### Update Visibility

```http
PUT /api/v1/permissions/{pipeline_id}/visibility
```

**Request Body:**
```json
{
  "visibility": "org"
}
```

### Grant Permission

```http
POST /api/v1/permissions/{pipeline_id}/grants
```

**Request Body:**
```json
{
  "principal_type": "user",
  "principal_id": "user_456",
  "level": "run",
  "expires_at": "2024-06-01T00:00:00Z"
}
```

### Remove Permission Grant

```http
DELETE /api/v1/permissions/{pipeline_id}/grants/{principal_type}/{principal_id}
```

### Check Permission

```http
GET /api/v1/permissions/{pipeline_id}/check?level=run
```

**Response:**
```json
{
  "has_access": true,
  "effective_level": "edit",
  "grant_source": "direct"
}
```

### Get Effective Permissions

```http
GET /api/v1/permissions/{pipeline_id}/effective
```

Returns detailed information about how permissions are resolved for the current user.

**Response:**
```json
{
  "pipeline_id": "pipe_abc123",
  "user_id": "current_user",
  "is_owner": false,
  "effective_level": "edit",
  "direct_grant": {
    "principal_type": "user",
    "principal_id": "current_user",
    "level": "edit"
  },
  "inherited_grants": [],
  "visibility_access": false,
  "can_view": true,
  "can_run": true,
  "can_edit": true,
  "can_admin": false
}
```

### Share Pipeline (Convenience Endpoint)

```http
POST /api/v1/permissions/{pipeline_id}/share
```

Share a pipeline with multiple users, organizations, or teams at once.

**Request Body:**
```json
{
  "users": ["user_123", "user_456"],
  "orgs": ["org_acme"],
  "teams": ["team_dev"],
  "level": "run",
  "make_public": false
}
```

### List Accessible Pipelines

```http
GET /api/v1/permissions/user/accessible?min_level=view
```

List all pipelines the current user can access at a minimum level.

## Python Integration

### Using Permission Dependencies

```python
from fastapi import Depends
from flowmason_studio.auth.permissions import (
    require_view,
    require_run,
    require_edit,
    require_admin,
    get_user_context,
    UserContext,
)

@router.get("/{pipeline_id}")
async def get_pipeline(
    pipeline_id: str,
    user: UserContext = Depends(require_view()),
):
    """Requires VIEW permission."""
    ...

@router.post("/{pipeline_id}/run")
async def run_pipeline(
    pipeline_id: str,
    user: UserContext = Depends(require_run()),
):
    """Requires RUN permission."""
    ...
```

### Manual Permission Checking

```python
from flowmason_studio.auth.permissions import (
    permission_checker,
    get_user_context,
)

@router.get("/{pipeline_id}/details")
async def get_details(
    pipeline_id: str,
    user: UserContext = Depends(get_user_context),
):
    # Check multiple permissions
    if permission_checker.can_edit(pipeline_id, user):
        # Show edit controls
        ...
    elif permission_checker.can_view(pipeline_id, user):
        # Read-only view
        ...
    else:
        raise HTTPException(status_code=403)
```

### Storage API

```python
from flowmason_studio.services.permission_storage import get_permission_storage
from flowmason_studio.models.permissions import (
    PermissionLevel,
    PipelineVisibility,
    PrincipalType,
)

storage = get_permission_storage()

# Create permissions for a new pipeline
perms = storage.create_pipeline_permissions(
    pipeline_id="pipe_123",
    owner_id="user_abc",
    visibility=PipelineVisibility.PRIVATE,
)

# Grant access
storage.add_grant(
    pipeline_id="pipe_123",
    principal_type=PrincipalType.USER,
    principal_id="user_xyz",
    level=PermissionLevel.RUN,
    granted_by="user_abc",
)

# Check access
has_access = storage.check_permission(
    pipeline_id="pipe_123",
    user_id="user_xyz",
    required_level=PermissionLevel.RUN,
)

# Get effective permissions
effective = storage.get_effective_permissions(
    pipeline_id="pipe_123",
    user_id="user_xyz",
    user_orgs=["org_acme"],
    user_teams=["team_dev"],
)
print(f"Can edit: {effective.can_edit}")
```

## Folder Inheritance

Pipelines can inherit permissions from parent folders:

```python
# Create folder permissions
storage.create_folder_permissions(
    folder_id="folder_projects",
    owner_id="user_admin",
    visibility=PipelineVisibility.ORG,
)

# Grant team access to folder
storage.add_folder_grant(
    folder_id="folder_projects",
    principal_type=PrincipalType.TEAM,
    principal_id="team_dev",
    level=PermissionLevel.EDIT,
    granted_by="user_admin",
)

# Pipeline in folder inherits permissions
storage.create_pipeline_permissions(
    pipeline_id="pipe_new",
    owner_id="user_abc",
    folder_id="folder_projects",  # Inherits from this folder
)
```

## OAuth Scope Integration

Pipeline permissions work alongside OAuth scopes:

| Scope | Permissions |
|-------|-------------|
| `full` | All operations |
| `read` | List/get pipelines, view executions |
| `execute` | Run pipelines (requires `run` permission) |
| `write` | Create/modify pipelines (requires `edit` permission) |

Both scope AND pipeline permission must be satisfied:

```python
from flowmason_studio.auth.permissions import require_scope, require_run

@router.post("/{pipeline_id}/run")
async def run_pipeline(
    pipeline_id: str,
    user: UserContext = Depends(require_scope("execute")),
    _: UserContext = Depends(require_run()),
):
    """Requires both 'execute' scope AND 'run' permission."""
    ...
```

## Best Practices

1. **Least Privilege**: Grant the minimum permission level needed
2. **Use Teams**: Organize users into teams for easier management
3. **Folder Structure**: Use folders to organize pipelines and share permissions
4. **Expiring Grants**: Use expiration for temporary access
5. **Audit**: Track `granted_by` for permission auditing
6. **Visibility**: Start with `private`, expand as needed

## Troubleshooting

### Permission Denied

1. Check effective permissions: `GET /permissions/{pipeline_id}/effective`
2. Verify JWT token contains correct user ID
3. Check if user is in required org/team
4. Verify grant hasn't expired

### Inheritance Not Working

1. Verify `inherit_from_folder` is `true`
2. Check folder permissions exist
3. Verify folder hierarchy (no circular references)

### API Key Access

1. API keys need explicit grants or public visibility
2. Check API key scopes match operation
3. Use principal type `api_key` for API key grants


---

## 05-security/secrets-rotation-audit.md

# Secrets Rotation & Audit

FlowMason provides comprehensive secrets management with automatic rotation policies and full audit logging for compliance and security monitoring.

## Overview

The secrets service provides:
- **Encryption**: Fernet (AES-128) symmetric encryption
- **Key Derivation**: PBKDF2 with per-organization salts
- **Rotation Policies**: Scheduled and automatic rotation
- **Audit Logging**: Complete access history with actor tracking
- **Expiration**: Optional secret expiration with warnings

## Basic Usage

```python
from flowmason_studio.services.secrets import get_secrets_service

# Get secrets service for your organization
secrets = get_secrets_service("my-org")

# Store a secret
secrets.set(
    name="OPENAI_API_KEY",
    value="sk-...",
    description="OpenAI API key for production",
    category="api_key",
    created_by="user@example.com",
)

# Retrieve a secret
value = secrets.get("OPENAI_API_KEY", actor="user@example.com")
```

## Rotation Policies

### Setting a Rotation Policy

```python
# Set a 90-day rotation policy with 7-day warning
policy = secrets.set_rotation_policy(
    secret_name="OPENAI_API_KEY",
    rotation_interval_days=90,
    notify_before_days=7,
    auto_rotate=False,
    actor="admin@example.com",
)

print(f"Next rotation: {policy.next_rotation}")
```

### Checking Rotation Status

```python
# Get secrets due for rotation
due_secrets = secrets.get_secrets_due_for_rotation()

for policy in due_secrets:
    print(f"{policy.secret_name}: due on {policy.next_rotation}")
```

### Manual Secret Rotation

```python
# Rotate a secret with a new value
secrets.rotate_secret(
    secret_name="OPENAI_API_KEY",
    new_value="sk-new-key...",
    actor="admin@example.com",
    actor_ip="192.168.1.100",
)
```

### Automatic Rotation

For secrets that can be automatically rotated (e.g., database passwords), you can register rotation handlers:

```python
# Define a rotation handler
def rotate_db_password(secret_name: str, current_value: str) -> str:
    import secrets as py_secrets
    new_password = py_secrets.token_urlsafe(32)
    # Update database with new password here
    return new_password

# Register the handler
secrets.register_rotation_handler("db_password_rotator", rotate_db_password)

# Set policy with auto-rotation
secrets.set_rotation_policy(
    secret_name="DATABASE_PASSWORD",
    rotation_interval_days=30,
    auto_rotate=True,
    rotation_handler="db_password_rotator",
)

# Run auto-rotations (typically via scheduler)
rotated = secrets.run_auto_rotations(actor="system:scheduler")
print(f"Rotated secrets: {rotated}")
```

### Master Key Rotation

Rotate the master encryption key to re-encrypt all secrets:

```python
# Rotate master key (re-encrypts all secrets)
count = secrets.rotate_key(
    new_master_key="new-secure-master-key-32chars",
    actor="admin@example.com",
)
print(f"Re-encrypted {count} secrets")
```

## Audit Logging

All secret operations are automatically logged with full context.

### Logged Actions

| Action | Description |
|--------|-------------|
| `create` | New secret created |
| `read` | Secret value accessed |
| `update` | Secret value updated |
| `delete` | Secret deleted |
| `rotate_key` | Master key rotated |
| `rotation_scheduled` | Rotation policy created |
| `rotation_completed` | Secret rotated |
| `expiration_warning` | Secret nearing expiration |
| `access_denied` | Access attempt failed |

### Querying Audit Logs

```python
from datetime import datetime, timedelta

# Get all logs from the last 7 days
logs = secrets.get_audit_logs(
    start_date=datetime.now() - timedelta(days=7),
    end_date=datetime.now(),
    limit=100,
)

for log in logs:
    print(f"[{log.timestamp}] {log.action} on {log.secret_name} by {log.actor}")
```

### Filter by Secret

```python
# Get access history for a specific secret
history = secrets.get_secret_access_history("OPENAI_API_KEY", days=30)

print(f"Access count: {len(history)}")
for entry in history:
    print(f"  {entry.timestamp}: {entry.action} by {entry.actor}")
```

### Filter by Actor

```python
# Get all activity by a specific user
activity = secrets.get_actor_activity("user@example.com", days=30)

for entry in activity:
    print(f"  {entry.timestamp}: {entry.action} on {entry.secret_name}")
```

### Failed Access Attempts

```python
# Get failed access attempts (security monitoring)
failures = secrets.get_failed_access_attempts(days=7)

if failures:
    print(f"WARNING: {len(failures)} failed access attempts!")
    for entry in failures:
        print(f"  {entry.timestamp}: {entry.secret_name}")
        print(f"    Actor: {entry.actor}, IP: {entry.actor_ip}")
        print(f"    Error: {entry.error_message}")
```

### Export Audit Logs

```python
# Export to JSON
json_export = secrets.export_audit_logs(
    start_date=datetime(2024, 1, 1),
    end_date=datetime.now(),
    format="json",
)

# Export to CSV
csv_export = secrets.export_audit_logs(
    start_date=datetime(2024, 1, 1),
    end_date=datetime.now(),
    format="csv",
)

# Save to file
with open("secrets_audit.csv", "w") as f:
    f.write(csv_export)
```

## Audit Log Entry Fields

Each audit log entry contains:

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique entry ID |
| `timestamp` | string | ISO 8601 timestamp |
| `action` | string | Action type (see above) |
| `secret_name` | string | Name of the secret |
| `org_id` | string | Organization ID |
| `actor` | string | User/system performing action |
| `actor_ip` | string | IP address of actor |
| `details` | object | Additional context |
| `success` | boolean | Whether action succeeded |
| `error_message` | string | Error details if failed |

## Storage

Audit logs are stored in JSONL format (one entry per line) organized by date:

```
~/.flowmason/secrets/<org-hash>/
├── <secret-hash>.secret     # Encrypted secret value
├── <secret-hash>.meta       # Secret metadata
├── policies/
│   └── <secret-hash>.policy # Rotation policy
└── audit/
    ├── 2024-01-01.jsonl     # Daily audit logs
    ├── 2024-01-02.jsonl
    └── ...
```

## Security Best Practices

1. **Set FLOWMASON_SECRETS_KEY**: Use a strong master key in production
   ```bash
   export FLOWMASON_SECRETS_KEY="your-32-character-master-key..."
   ```

2. **Rotate Keys Regularly**: Rotate master keys quarterly or after security incidents

3. **Monitor Failed Attempts**: Set up alerts for failed access attempts

4. **Review Audit Logs**: Regularly review who is accessing secrets

5. **Use Expiration**: Set expiration dates for temporary secrets

6. **Limit Access**: Only grant secret access to required services/users

## API Reference

### SecretsService Methods

#### Rotation Policy Management

| Method | Description |
|--------|-------------|
| `set_rotation_policy()` | Create/update rotation policy |
| `get_rotation_policy()` | Get policy for a secret |
| `delete_rotation_policy()` | Remove rotation policy |
| `list_rotation_policies()` | List all policies |
| `get_secrets_due_for_rotation()` | Get secrets needing rotation |
| `rotate_secret()` | Rotate a specific secret |
| `register_rotation_handler()` | Register auto-rotation handler |
| `run_auto_rotations()` | Execute due auto-rotations |
| `rotate_key()` | Rotate master encryption key |

#### Audit Log Queries

| Method | Description |
|--------|-------------|
| `get_audit_logs()` | Query audit logs with filters |
| `get_secret_access_history()` | Get history for a secret |
| `get_actor_activity()` | Get activity by actor |
| `get_failed_access_attempts()` | Get failed attempts |
| `export_audit_logs()` | Export logs to JSON/CSV |

## Integration Example

```python
from datetime import datetime, timedelta
from flowmason_studio.services.secrets import get_secrets_service

# Initialize
secrets = get_secrets_service("production")

# Create a secret with rotation policy
secrets.set(
    name="API_KEY",
    value="secret-value",
    category="api_key",
    created_by="admin",
)

secrets.set_rotation_policy(
    secret_name="API_KEY",
    rotation_interval_days=90,
    notify_before_days=14,
    actor="admin",
)

# Use the secret (automatically logged)
api_key = secrets.get("API_KEY", actor="service:api-gateway")

# Check rotation status
due = secrets.get_secrets_due_for_rotation()
for policy in due:
    print(f"Rotate {policy.secret_name} by {policy.next_rotation}")

# Review recent activity
logs = secrets.get_audit_logs(
    start_date=datetime.now() - timedelta(days=1),
    limit=50,
)
print(f"Last 24h: {len(logs)} secret operations")
```


---

## 06-studio/ai-copilot.md

# AI Co-pilot

The FlowMason AI Co-pilot provides intelligent assistance for designing, debugging, and optimizing pipelines using large language models.

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│  AI Co-pilot                                              [Ask] │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  User: "Add error handling to the API call stage"               │
│                                                                 │
│  Co-pilot: I'll wrap the http-request stage in a trycatch       │
│  with retry logic. Here's my suggestion:                        │
│                                                                 │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │ + trycatch: api-with-retry                               │   │
│  │   ├── try: http-request (existing)                       │   │
│  │   ├── catch: error-handler (new)                         │   │
│  │   └── retry: 3 attempts, exponential backoff             │   │
│  └─────────────────────────────────────────────────────────┘   │
│                                                                 │
│  [Apply Changes]  [Modify]  [Explain]  [Reject]                │
└─────────────────────────────────────────────────────────────────┘
```

## Features

### 1. Pipeline Suggestions

Get AI-powered suggestions for improving your pipelines.

```python
from flowmason_core.copilot import CopilotService, CopilotContext

# Initialize service
copilot = CopilotService(api_key="your-anthropic-key")

# Create context from your pipeline
context = CopilotContext.from_pipeline(pipeline)

# Get suggestions
suggestion = await copilot.suggest(
    context=context,
    request="Add error handling to the API call"
)

print(f"Suggestion: {suggestion.description}")
print(f"Changes: {suggestion.config}")
print(f"Reasoning: {suggestion.reasoning}")
```

### 2. Pipeline Explanation

Understand complex pipelines with AI-generated explanations.

```python
explanation = await copilot.explain(
    context=context,
    target="process-data"  # Specific stage or None for whole pipeline
)

print(explanation.summary)
print(explanation.details)
```

### 3. Pipeline Generation

Generate entire pipelines from natural language descriptions.

```python
pipeline = await copilot.generate(
    description="Create a pipeline that fetches user data from an API, "
                "validates the schema, transforms it to our format, "
                "and saves to the database"
)
```

### 4. Optimization Suggestions

Get recommendations for improving pipeline performance.

```python
optimizations = await copilot.optimize(context=context)

for opt in optimizations:
    print(f"- {opt.description}")
    print(f"  Impact: {opt.impact}")
    print(f"  Effort: {opt.effort}")
```

### 5. Debug Assistance

Get help debugging pipeline issues.

```python
debug_help = await copilot.debug(
    context=context,
    error_message="Stage 'transform' failed: KeyError 'user_id'",
    execution_logs=logs
)

print(f"Root cause: {debug_help.root_cause}")
print(f"Suggested fix: {debug_help.suggestion}")
```

## API Endpoints

The Studio backend provides REST endpoints for co-pilot functionality:

### POST /api/v1/copilot/suggest
```json
{
  "pipeline_id": "my-pipeline",
  "request": "Add validation before the transform stage"
}
```

### POST /api/v1/copilot/explain
```json
{
  "pipeline_id": "my-pipeline",
  "stage_id": "transform"  // optional
}
```

### POST /api/v1/copilot/generate
```json
{
  "description": "Pipeline that processes customer feedback"
}
```

### POST /api/v1/copilot/optimize
```json
{
  "pipeline_id": "my-pipeline"
}
```

### POST /api/v1/copilot/debug
```json
{
  "pipeline_id": "my-pipeline",
  "run_id": "run-123",
  "error": "KeyError: 'user_id'"
}
```

## Context Serialization

The co-pilot uses a structured context to understand your pipeline:

```python
from flowmason_core.copilot import (
    CopilotContext, PipelineSnapshot, StageSnapshot, RegistrySnapshot
)

# Manual context creation
context = CopilotContext(
    pipeline=PipelineSnapshot(
        id="my-pipeline",
        name="My Pipeline",
        stages=[
            StageSnapshot(
                id="fetch",
                component_type="http_request",
                config={"url": "https://api.example.com"}
            )
        ]
    ),
    registry=RegistrySnapshot(
        available_components=["http_request", "json_transform", "logger"]
    )
)
```

## VSCode Integration

Access the AI Co-pilot directly from VSCode:

### Sidebar Panel
1. Open the FlowMason sidebar
2. Click on "AI Co-pilot" tab
3. Type your request and press Enter

### Inline Suggestions
- Hover over a stage and click "Ask AI"
- Use `Cmd+K` (Mac) or `Ctrl+K` (Windows) for quick actions

### Commands
- `FlowMason: Ask AI Co-pilot`
- `FlowMason: Explain Pipeline`
- `FlowMason: Optimize Pipeline`
- `FlowMason: Generate Pipeline from Description`

## Configuration

Configure the co-pilot in your settings:

```json
{
  "flowmason.copilot.enabled": true,
  "flowmason.copilot.model": "claude-3-opus",
  "flowmason.copilot.maxTokens": 4096,
  "flowmason.copilot.temperature": 0.7
}
```

Environment variables:
```bash
ANTHROPIC_API_KEY=your-api-key
FLOWMASON_COPILOT_MODEL=claude-3-opus
```

## Best Practices

1. **Be Specific**: Provide clear, specific requests for better suggestions
2. **Review Changes**: Always review AI suggestions before applying
3. **Iterate**: Use "Modify" to refine suggestions that are close but not perfect
4. **Provide Context**: Include relevant information about your use case
5. **Use Explain**: Use the explain feature to understand complex pipelines


---

## 06-studio/ai-insights.md

# Execution Analytics & AI Insights

FlowMason Studio provides AI-powered analytics that automatically detect patterns, anomalies, and optimization opportunities in your pipeline executions.

## Overview

The insights engine analyzes your execution history to provide:

- **Cost Analysis**: Track spending, detect spikes, forecast future costs
- **Performance Monitoring**: Identify degradation, latency outliers, slow stages
- **Reliability Tracking**: Failure patterns, error type distribution, MTTR
- **Usage Patterns**: Peak hours, busiest pipelines, model preferences
- **Optimization Recommendations**: Model selection, cost reduction opportunities

## Quick Start

### Get Insights Summary

```http
GET /api/v1/analytics/insights/summary
```

Returns the most important insights at a glance:

```json
{
  "generated_at": "2024-01-15T10:30:00Z",
  "total_insights": 5,
  "critical_count": 1,
  "warning_count": 2,
  "info_count": 2,
  "top_cost_insight": {
    "type": "cost_spike",
    "severity": "warning",
    "title": "Cost increased by 45%",
    "description": "Spending increased from $12.50 to $18.12..."
  },
  "top_performance_insight": null,
  "top_reliability_insight": {
    "type": "failure_pattern",
    "severity": "critical",
    "title": "Critical failure rate: 28%"
  },
  "estimated_savings": 8.50,
  "performance_change_percent": -5.2,
  "reliability_change_percent": 3.1
}
```

### Get Full Report

```http
GET /api/v1/analytics/insights/report?days=30
```

Returns a comprehensive analysis including:

- Trend analysis (cost, usage, performance, reliability)
- Cost breakdown by provider, model, and pipeline
- Performance metrics (p50, p95, p99 latency)
- Failure analysis with error type distribution
- Cost forecasting
- Optimization opportunities

### Get Filtered Insights

```http
GET /api/v1/analytics/insights?category=cost&severity=warning
```

Filter insights by:
- `category`: cost, performance, reliability, usage, optimization
- `severity`: critical, warning, info
- `pipeline_id`: Focus on a specific pipeline

## Insight Types

### Cost Insights

| Type | Description | Severity |
|------|-------------|----------|
| `cost_spike` | Spending increased significantly | Warning/Critical |
| `cost_optimization` | Model concentration or waste detected | Info |
| `model_recommendation` | Cheaper model could be used | Info |

**Example:**
```json
{
  "type": "cost_spike",
  "severity": "warning",
  "category": "cost",
  "title": "Cost increased by 45%",
  "description": "Spending increased from $12.50 to $18.12 compared to the previous period.",
  "data": {
    "previous_cost": 12.50,
    "current_cost": 18.12,
    "increase_percent": 45
  },
  "recommendations": [
    "Review usage patterns to identify unexpected increases",
    "Consider using smaller models for simple tasks",
    "Check for runaway or stuck pipelines"
  ]
}
```

### Performance Insights

| Type | Description | Severity |
|------|-------------|----------|
| `performance_degradation` | Execution time increased significantly | Warning |
| `performance_improvement` | Execution time decreased | Info |
| `anomaly` | High latency variability detected | Info |

**Example:**
```json
{
  "type": "performance_degradation",
  "severity": "warning",
  "category": "performance",
  "title": "Execution time increased by 35%",
  "description": "Average execution time increased from 1200ms to 1620ms.",
  "data": {
    "previous_avg_ms": 1200,
    "current_avg_ms": 1620
  },
  "recommendations": [
    "Check for slow API responses or rate limiting",
    "Review any recent pipeline changes",
    "Consider caching repeated operations"
  ]
}
```

### Reliability Insights

| Type | Description | Severity |
|------|-------------|----------|
| `failure_pattern` | High or elevated failure rate | Critical/Warning |
| `reliability` | Reliability issues detected | Warning |

**Example:**
```json
{
  "type": "failure_pattern",
  "severity": "critical",
  "category": "reliability",
  "title": "Critical failure rate: 28%",
  "description": "42 of 150 runs failed. Immediate attention required.",
  "data": {
    "failure_rate": 0.28,
    "total_failures": 42,
    "by_error_type": {
      "api_error": 25,
      "timeout": 12,
      "validation_error": 5
    }
  },
  "recommendations": [
    "Check recent changes to pipelines or configurations",
    "Verify API credentials and rate limits",
    "Review error logs for root cause"
  ]
}
```

## Trends and Analysis

### Trend Direction

Each metric includes trend analysis:

```json
{
  "cost_trend": {
    "metric_name": "cost",
    "current_value": 18.12,
    "previous_value": 12.50,
    "change_percent": 44.96,
    "direction": "up",
    "is_significant": true
  }
}
```

Directions: `up`, `down`, `stable`

### Performance Metrics

```json
{
  "performance_metrics": {
    "avg_duration_ms": 1250,
    "p50_duration_ms": 1100,
    "p95_duration_ms": 2800,
    "p99_duration_ms": 4500,
    "slowest_stages": [],
    "fastest_stages": []
  }
}
```

### Failure Analysis

```json
{
  "failure_analysis": {
    "total_failures": 42,
    "failure_rate": 0.28,
    "by_error_type": {
      "api_error": 25,
      "timeout": 12,
      "validation_error": 5
    },
    "by_pipeline": {
      "pipeline_abc": 30,
      "pipeline_xyz": 12
    },
    "common_patterns": [
      "Most failures (25) are api_error",
      "Pipeline pipeline_abc accounts for most failures"
    ]
  }
}
```

## Cost Forecasting

```json
{
  "cost_forecast": {
    "current_daily_avg": 2.50,
    "projected_daily": 2.75,
    "projected_weekly": 19.25,
    "projected_monthly": 82.50,
    "trend": "up",
    "confidence": 0.85
  }
}
```

## Optimization Opportunities

The insights engine identifies actionable optimization opportunities:

```json
{
  "optimization_opportunities": [
    {
      "type": "model_downgrade",
      "description": "Switch from claude-3-opus to claude-3-haiku for simple tasks",
      "current_cost": 45.00,
      "potential_savings": 31.50,
      "savings_percent": 70,
      "recommendation": "Route simpler tasks to claude-3-haiku which is significantly cheaper",
      "difficulty": "medium"
    },
    {
      "type": "reliability",
      "description": "Reduce failures to cut wasted resources",
      "current_cost": 5.60,
      "potential_savings": 4.48,
      "savings_percent": 22,
      "recommendation": "Address common failure causes to reduce wasted API calls",
      "difficulty": "medium"
    }
  ]
}
```

## Model Efficiency

Compare efficiency across models:

```json
{
  "model_efficiency": [
    {
      "provider": "anthropic",
      "model": "claude-3-5-sonnet-20241022",
      "avg_latency_ms": 1200,
      "avg_tokens_per_request": 850,
      "cost_per_1k_tokens": 0.0045,
      "success_rate": 0.98,
      "usage_count": 1250
    },
    {
      "provider": "openai",
      "model": "gpt-4o-mini",
      "avg_latency_ms": 800,
      "avg_tokens_per_request": 620,
      "cost_per_1k_tokens": 0.00015,
      "success_rate": 0.99,
      "usage_count": 850
    }
  ]
}
```

## Python Integration

```python
from flowmason_studio.services.insights_service import get_insights_service

# Get insights service
service = get_insights_service()

# Generate full report
report = service.generate_report(
    org_id="default",
    days=30,
    include_recommendations=True,
    include_forecasts=True,
)

# Print summary
print(f"Total insights: {len(report.insights)}")
print(f"Estimated savings: ${sum(o.potential_savings for o in report.optimization_opportunities):.2f}")

# Check for critical issues
critical = [i for i in report.insights if i.severity.value == "critical"]
if critical:
    print(f"ALERT: {len(critical)} critical issues detected!")
    for insight in critical:
        print(f"  - {insight.title}")

# Get quick summary
summary = service.get_summary(org_id="default", days=7)
print(f"Critical: {summary.critical_count}")
print(f"Warnings: {summary.warning_count}")

# Filter insights by category
cost_insights = service.get_insights(
    org_id="default",
    days=7,
    category=InsightCategory.COST,
)
```

## Thresholds

The insights engine uses these thresholds for detection:

| Metric | Warning | Critical |
|--------|---------|----------|
| Cost spike | 50% increase | 100% increase |
| Failure rate | 10% | 25% |
| Performance degradation | 30% slower | N/A |
| Significant change | 10% | N/A |

## Best Practices

1. **Review daily**: Check the insights summary daily for critical issues
2. **Act on critical**: Address critical severity insights immediately
3. **Track trends**: Monitor trend directions over time
4. **Optimize incrementally**: Address one optimization opportunity at a time
5. **Set alerts**: Integrate with webhooks to alert on critical insights
6. **Compare periods**: Use different time ranges to spot patterns

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/analytics/insights/report` | GET | Full insights report |
| `/analytics/insights/summary` | GET | Quick summary |
| `/analytics/insights` | GET | Filtered insights list |

### Query Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `org_id` | string | "default" | Organization ID |
| `days` | int | 7-30 | Analysis period |
| `pipeline_id` | string | null | Filter by pipeline |
| `category` | enum | null | cost/performance/reliability/usage/optimization |
| `severity` | enum | null | critical/warning/info |
| `include_recommendations` | bool | true | Include recommendations |
| `include_forecasts` | bool | true | Include cost forecasts |


---

## 06-studio/analytics.md

# Analytics API

FlowMason Studio provides an analytics API for dashboard metrics and statistics. These endpoints power the Operations Dashboard and provide insights into pipeline execution.

## Overview

The analytics API provides:
- Execution metrics and success rates
- Per-pipeline statistics
- Daily and hourly trends
- Recent activity feed
- Usage summaries

## Dashboard Overview

Get a complete dashboard overview in a single call:

```bash
curl "http://localhost:8999/api/v1/analytics/overview?days=7&limit=5"
```

Response:
```json
{
  "metrics": {
    "total_runs": 150,
    "successful_runs": 135,
    "failed_runs": 12,
    "cancelled_runs": 2,
    "running_runs": 1,
    "success_rate": 0.9,
    "avg_duration_seconds": 45.2
  },
  "top_pipelines": [
    {
      "pipeline_id": "pipe_abc123",
      "pipeline_name": "Data ETL",
      "total_runs": 50,
      "successful_runs": 48,
      "failed_runs": 2,
      "success_rate": 0.96,
      "avg_duration_seconds": 30.5,
      "last_run_at": "2024-01-15T10:30:00Z"
    }
  ],
  "daily_stats": [
    {
      "date": "2024-01-15",
      "total_runs": 25,
      "successful_runs": 23,
      "failed_runs": 2
    }
  ],
  "recent_activity": [
    {
      "run_id": "run_xyz789",
      "pipeline_id": "pipe_abc123",
      "pipeline_name": "Data ETL",
      "status": "completed",
      "started_at": "2024-01-15T10:30:00Z",
      "completed_at": "2024-01-15T10:30:45Z",
      "duration_seconds": 45.0
    }
  ]
}
```

## Execution Metrics

Get aggregate execution metrics:

```bash
curl "http://localhost:8999/api/v1/analytics/metrics?days=7"
```

Filter by pipeline:
```bash
curl "http://localhost:8999/api/v1/analytics/metrics?days=7&pipeline_id=pipe_abc123"
```

Response:
```json
{
  "total_runs": 150,
  "successful_runs": 135,
  "failed_runs": 12,
  "cancelled_runs": 2,
  "running_runs": 1,
  "success_rate": 0.9,
  "avg_duration_seconds": 45.2
}
```

## Pipeline Metrics

Get per-pipeline statistics:

```bash
curl "http://localhost:8999/api/v1/analytics/pipelines?days=7&limit=20&sort_by=runs"
```

Sort options:
- `runs` - Most runs first (default)
- `success_rate` - Highest success rate first
- `name` - Alphabetical

Response:
```json
[
  {
    "pipeline_id": "pipe_abc123",
    "pipeline_name": "Data ETL",
    "total_runs": 50,
    "successful_runs": 48,
    "failed_runs": 2,
    "success_rate": 0.96,
    "avg_duration_seconds": 30.5,
    "last_run_at": "2024-01-15T10:30:00Z"
  },
  {
    "pipeline_id": "pipe_def456",
    "pipeline_name": "Content Generator",
    "total_runs": 35,
    "successful_runs": 30,
    "failed_runs": 5,
    "success_rate": 0.857,
    "avg_duration_seconds": 120.3,
    "last_run_at": "2024-01-15T09:00:00Z"
  }
]
```

## Daily Statistics

Get daily run counts for charting:

```bash
curl "http://localhost:8999/api/v1/analytics/daily?days=30"
```

Filter by pipeline:
```bash
curl "http://localhost:8999/api/v1/analytics/daily?days=30&pipeline_id=pipe_abc123"
```

Response:
```json
[
  {
    "date": "2024-01-01",
    "total_runs": 15,
    "successful_runs": 14,
    "failed_runs": 1
  },
  {
    "date": "2024-01-02",
    "total_runs": 20,
    "successful_runs": 18,
    "failed_runs": 2
  }
]
```

## Hourly Distribution

Get aggregated hourly distribution:

```bash
curl "http://localhost:8999/api/v1/analytics/hourly?days=7"
```

Response:
```json
[
  {"hour": 0, "total_runs": 5, "successful_runs": 5, "failed_runs": 0},
  {"hour": 1, "total_runs": 3, "successful_runs": 3, "failed_runs": 0},
  {"hour": 9, "total_runs": 25, "successful_runs": 23, "failed_runs": 2},
  {"hour": 10, "total_runs": 30, "successful_runs": 28, "failed_runs": 2}
]
```

This is useful for understanding when pipelines are most active.

## Recent Activity

Get recent execution activity:

```bash
curl "http://localhost:8999/api/v1/analytics/recent?limit=20"
```

Filter by status:
```bash
curl "http://localhost:8999/api/v1/analytics/recent?limit=20&status=failed"
```

Response:
```json
[
  {
    "run_id": "run_xyz789",
    "pipeline_id": "pipe_abc123",
    "pipeline_name": "Data ETL",
    "status": "completed",
    "started_at": "2024-01-15T10:30:00Z",
    "completed_at": "2024-01-15T10:30:45Z",
    "duration_seconds": 45.0
  },
  {
    "run_id": "run_abc123",
    "pipeline_id": "pipe_def456",
    "pipeline_name": "Content Generator",
    "status": "failed",
    "started_at": "2024-01-15T10:25:00Z",
    "completed_at": "2024-01-15T10:25:30Z",
    "duration_seconds": 30.0
  }
]
```

## Usage Summary

Get overall usage summary:

```bash
curl "http://localhost:8999/api/v1/analytics/usage?days=30"
```

Response:
```json
{
  "period": "last_30_days",
  "total_pipelines": 25,
  "active_pipelines": 15,
  "total_runs": 450,
  "total_stages_executed": 1800,
  "avg_stages_per_run": 4.0
}
```

## Query Parameters

### Common Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `days` | int | 7 | Number of days to include (1-90) |
| `limit` | int | varies | Maximum items to return |
| `pipeline_id` | string | - | Filter by pipeline |

### Sort Options (Pipeline Metrics)

| Value | Description |
|-------|-------------|
| `runs` | Sort by total run count (default) |
| `success_rate` | Sort by success rate |
| `name` | Sort alphabetically |

## Use Cases

### Operations Dashboard

```javascript
// Fetch complete dashboard data
const response = await fetch('/api/v1/analytics/overview?days=7&limit=5');
const data = await response.json();

// Display metrics
console.log(`Success Rate: ${(data.metrics.success_rate * 100).toFixed(1)}%`);
console.log(`Total Runs: ${data.metrics.total_runs}`);
console.log(`Average Duration: ${data.metrics.avg_duration_seconds?.toFixed(1)}s`);
```

### Chart Data

```javascript
// Get daily stats for line chart
const daily = await fetch('/api/v1/analytics/daily?days=30');
const dailyData = await daily.json();

// Format for chart library
const chartData = dailyData.map(d => ({
  date: d.date,
  success: d.successful_runs,
  failed: d.failed_runs
}));
```

### Pipeline Health Monitoring

```javascript
// Get pipelines sorted by success rate
const pipelines = await fetch('/api/v1/analytics/pipelines?sort_by=success_rate&limit=10');
const data = await pipelines.json();

// Find low-performing pipelines
const troubled = data.filter(p => p.success_rate < 0.9);
console.log('Pipelines needing attention:', troubled);
```

### Real-time Activity Feed

```javascript
// Poll for recent activity
async function pollActivity() {
  const response = await fetch('/api/v1/analytics/recent?limit=10');
  const activity = await response.json();
  updateActivityFeed(activity);
}

setInterval(pollActivity, 5000); // Every 5 seconds
```

## Response Codes

| Code | Description |
|------|-------------|
| 200 | Success |
| 400 | Invalid parameters (e.g., days > 90) |
| 500 | Server error |

## Performance Notes

- Data is calculated in real-time from stored runs
- For large datasets, consider using smaller `days` values
- The `/overview` endpoint combines multiple queries for efficiency
- Use specific endpoints when you only need partial data


---

## 06-studio/collaboration.md

# Real-time Collaboration

FlowMason Studio supports real-time collaborative editing of pipelines with multiple users.

## Overview

Real-time Collaboration provides:

- **Live Cursors**: See other users' cursor positions in real-time
- **Presence Awareness**: Know who's online and what they're editing
- **Synchronized Editing**: Changes propagate instantly to all participants
- **Conflict Resolution**: Automatic handling of concurrent edits
- **Element Locking**: Prevent conflicts on specific elements
- **Chat & Comments**: In-context communication
- **Undo/Redo**: Per-user undo history
- **Activity Log**: Track all session changes

## Quick Start

### Create a Session

```http
POST /api/v1/collaboration/sessions
Content-Type: application/json

{
  "pipeline_id": "my-pipeline-id",
  "max_participants": 10,
  "auto_save": true,
  "allow_anonymous": false
}
```

**Response:**
```json
{
  "session": {
    "id": "session_abc123",
    "pipeline_id": "my-pipeline-id",
    "created_at": "2024-01-15T10:00:00Z",
    "created_by": "user_owner",
    "is_active": true,
    "participants": [
      {
        "user_id": "user_owner",
        "username": "Pipeline Owner",
        "role": "owner",
        "status": "online",
        "color": "#ef4444"
      }
    ],
    "current_version": 1
  },
  "join_url": "/collaborate/session_abc123",
  "invite_code": "ABC12345"
}
```

### Join a Session

By session ID:
```http
POST /api/v1/collaboration/sessions/join
Content-Type: application/json

{
  "session_id": "session_abc123",
  "username": "Collaborator"
}
```

Or by invite code:
```http
POST /api/v1/collaboration/sessions/join
Content-Type: application/json

{
  "invite_code": "ABC12345",
  "username": "Collaborator"
}
```

**Response:**
```json
{
  "session": {...},
  "user": {
    "user_id": "user_123",
    "username": "Collaborator",
    "role": "editor",
    "status": "online",
    "color": "#3b82f6"
  },
  "token": "ws_token_session_abc123_user_123"
}
```

## WebSocket Connection

Connect to the WebSocket for real-time updates:

```
ws://localhost:8999/api/v1/collaboration/ws/session_abc123
```

### Message Protocol

**Cursor Movement:**
```json
{
  "type": "cursor",
  "x": 250,
  "y": 150,
  "viewport_x": 0,
  "viewport_y": 0,
  "zoom": 1.0,
  "selected_stage": "generator_1"
}
```

**Send Edit:**
```json
{
  "type": "edit",
  "operation": "update_stage",
  "target_id": "generator_1",
  "data": {"config": {"prompt": "New prompt"}},
  "base_version": 5
}
```

**Chat Message:**
```json
{
  "type": "chat",
  "content": "Let's add a filter stage here",
  "mentions": ["user_123"]
}
```

**Typing Indicator:**
```json
{
  "type": "typing",
  "is_typing": true
}
```

### Events Received

**User Joined:**
```json
{
  "type": "user_joined",
  "session_id": "session_abc123",
  "user_id": "user_456",
  "data": {
    "user": {
      "user_id": "user_456",
      "username": "New User",
      "color": "#22c55e"
    }
  }
}
```

**Cursor Move:**
```json
{
  "type": "cursor_move",
  "user_id": "user_456",
  "data": {
    "cursor": {"x": 300, "y": 200},
    "selected_stage": "filter_1"
  }
}
```

**Edit Applied:**
```json
{
  "type": "edit",
  "user_id": "user_456",
  "data": {
    "change": {
      "id": "change_xyz",
      "operation": "update_stage",
      "target_id": "generator_1",
      "data": {...},
      "version": 6
    }
  }
}
```

## Presence

### Get Online Users

```http
GET /api/v1/collaboration/sessions/{session_id}/users
```

**Response:**
```json
[
  {
    "user_id": "user_owner",
    "username": "Pipeline Owner",
    "role": "owner",
    "status": "online",
    "cursor": {
      "position": {"x": 100, "y": 200},
      "selected_stage": "generator_1",
      "color": "#ef4444"
    },
    "color": "#ef4444"
  },
  {
    "user_id": "user_123",
    "username": "Collaborator",
    "role": "editor",
    "status": "online",
    "cursor": {...},
    "color": "#3b82f6"
  }
]
```

### Update Presence

```http
PUT /api/v1/collaboration/sessions/{session_id}/presence
Content-Type: application/json

{
  "status": "away",
  "cursor": {"x": 150, "y": 250},
  "selected_stage": "filter_1"
}
```

## Edit Operations

### Available Operations

| Operation | Description |
|-----------|-------------|
| `add_stage` | Add a new stage |
| `remove_stage` | Remove a stage |
| `update_stage` | Update stage config |
| `move_stage` | Change stage position |
| `add_connection` | Add a connection |
| `remove_connection` | Remove a connection |
| `update_pipeline` | Update pipeline metadata |
| `update_settings` | Update pipeline settings |

### Send an Edit

```http
POST /api/v1/collaboration/sessions/{session_id}/edits
Content-Type: application/json

{
  "operation": "add_stage",
  "target_id": null,
  "data": {
    "stage": {
      "id": "new_stage_1",
      "component_type": "filter",
      "config": {...}
    }
  },
  "base_version": 5
}
```

**Response (Success):**
```json
{
  "success": true,
  "change": {
    "id": "change_abc",
    "operation": "add_stage",
    "target_id": "new_stage_1",
    "data": {...},
    "user_id": "user_123",
    "version": 6
  },
  "new_version": 6
}
```

**Response (Conflict):**
```json
{
  "success": false,
  "conflict": {
    "id": "conflict_xyz",
    "change_a": {...},
    "change_b": {...},
    "conflict_type": "concurrent_edit"
  },
  "new_version": 7
}
```

### Sync Changes

Get all changes since a version:

```http
GET /api/v1/collaboration/sessions/{session_id}/edits?since_version=5
```

### Undo/Redo

```http
POST /api/v1/collaboration/sessions/{session_id}/undo
POST /api/v1/collaboration/sessions/{session_id}/redo
```

## Locking

Prevent concurrent edits on specific elements:

### Acquire Lock

```http
POST /api/v1/collaboration/sessions/{session_id}/locks
Content-Type: application/json

{
  "target_id": "generator_1",
  "target_type": "stage",
  "duration": 300,
  "reason": "Editing configuration"
}
```

**Response:**
```json
{
  "target_id": "generator_1",
  "target_type": "stage",
  "locked_by": "user_123",
  "locked_at": "2024-01-15T10:30:00Z",
  "expires_at": "2024-01-15T10:35:00Z",
  "reason": "Editing configuration"
}
```

### Release Lock

```http
DELETE /api/v1/collaboration/sessions/{session_id}/locks/generator_1
```

### Get Active Locks

```http
GET /api/v1/collaboration/sessions/{session_id}/locks
```

## Chat

### Send Message

```http
POST /api/v1/collaboration/sessions/{session_id}/chat
Content-Type: application/json

{
  "content": "Should we add error handling here?",
  "mentions": ["user_owner"]
}
```

### Get Messages

```http
GET /api/v1/collaboration/sessions/{session_id}/chat?limit=50
```

### Add Reaction

```http
POST /api/v1/collaboration/sessions/{session_id}/chat/{message_id}/reactions?emoji=👍
```

## Comments

Attach comments to specific pipeline elements:

### Add Comment

```http
POST /api/v1/collaboration/sessions/{session_id}/comments
Content-Type: application/json

{
  "target_type": "stage",
  "target_id": "generator_1",
  "content": "This prompt needs to be more specific"
}
```

### Reply to Comment

```http
POST /api/v1/collaboration/sessions/{session_id}/comments/{comment_id}/replies
Content-Type: application/json

{
  "content": "Good point, I'll update it"
}
```

### Resolve Comment

```http
POST /api/v1/collaboration/sessions/{session_id}/comments/{comment_id}/resolve
```

### Get Comments

```http
GET /api/v1/collaboration/sessions/{session_id}/comments?target_id=generator_1&include_resolved=false
```

## Invitations

### Invite User

```http
POST /api/v1/collaboration/sessions/{session_id}/invites
Content-Type: application/json

{
  "email": "collaborator@example.com",
  "role": "editor",
  "message": "Join me to work on this pipeline!"
}
```

### Accept Invite

```http
POST /api/v1/collaboration/invites/{invite_id}/accept
```

## Activity Log

```http
GET /api/v1/collaboration/sessions/{session_id}/activity?limit=50
```

**Response:**
```json
[
  {
    "id": "activity_1",
    "session_id": "session_abc123",
    "user_id": "user_owner",
    "username": "Pipeline Owner",
    "activity_type": "session_created",
    "description": "Pipeline Owner created the collaboration session",
    "timestamp": "2024-01-15T10:00:00Z"
  },
  {
    "id": "activity_2",
    "activity_type": "user_joined",
    "description": "Collaborator joined the session",
    "timestamp": "2024-01-15T10:05:00Z"
  }
]
```

## User Roles

| Role | Capabilities |
|------|--------------|
| `owner` | Full access, can end session, manage roles |
| `editor` | Can edit pipeline, chat, comment |
| `viewer` | Read-only access, can chat and comment |

## Session Settings

| Setting | Description |
|---------|-------------|
| `max_participants` | Maximum users allowed (2-50) |
| `auto_save` | Automatically save changes |
| `auto_save_interval` | Save interval in seconds |
| `allow_anonymous` | Allow anonymous users |
| `require_approval` | Require owner approval to join |

## Frontend Integration

### React Example

```tsx
import { useEffect, useState, useRef } from 'react';

function CollaborativeEditor({ sessionId, token }) {
  const ws = useRef<WebSocket>();
  const [users, setUsers] = useState([]);
  const [cursors, setCursors] = useState({});

  useEffect(() => {
    // Connect to WebSocket
    ws.current = new WebSocket(
      `ws://localhost:8999/api/v1/collaboration/ws/${sessionId}`
    );

    ws.current.onmessage = (event) => {
      const msg = JSON.parse(event.data);

      switch (msg.type) {
        case 'user_joined':
          setUsers(prev => [...prev, msg.data.user]);
          break;

        case 'user_left':
          setUsers(prev => prev.filter(u => u.user_id !== msg.user_id));
          break;

        case 'cursor_move':
          setCursors(prev => ({
            ...prev,
            [msg.user_id]: msg.data.cursor
          }));
          break;

        case 'edit':
          // Apply the edit to local state
          applyEdit(msg.data.change);
          break;
      }
    };

    return () => ws.current?.close();
  }, [sessionId]);

  const sendCursorUpdate = (x, y, selectedStage) => {
    ws.current?.send(JSON.stringify({
      type: 'cursor',
      x, y,
      selected_stage: selectedStage
    }));
  };

  const sendEdit = (operation, targetId, data, baseVersion) => {
    ws.current?.send(JSON.stringify({
      type: 'edit',
      operation,
      target_id: targetId,
      data,
      base_version: baseVersion
    }));
  };

  return (
    <div className="collaborative-editor">
      {/* User avatars */}
      <div className="user-list">
        {users.map(user => (
          <div
            key={user.user_id}
            className="user-avatar"
            style={{ borderColor: user.color }}
          >
            {user.username[0]}
          </div>
        ))}
      </div>

      {/* Canvas with cursors */}
      <div className="canvas" onMouseMove={handleMouseMove}>
        {Object.entries(cursors).map(([userId, cursor]) => (
          <div
            key={userId}
            className="cursor"
            style={{
              left: cursor.position.x,
              top: cursor.position.y,
              backgroundColor: cursor.color
            }}
          />
        ))}
        {/* Pipeline stages... */}
      </div>
    </div>
  );
}
```

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/collaboration/sessions` | POST | Create session |
| `/collaboration/sessions/{id}` | GET | Get session |
| `/collaboration/sessions/join` | POST | Join session |
| `/collaboration/sessions/{id}/leave` | POST | Leave session |
| `/collaboration/sessions/{id}/end` | POST | End session |
| `/collaboration/sessions/{id}/users` | GET | Get online users |
| `/collaboration/sessions/{id}/presence` | PUT | Update presence |
| `/collaboration/sessions/{id}/edits` | POST | Send edit |
| `/collaboration/sessions/{id}/edits` | GET | Get changes |
| `/collaboration/sessions/{id}/undo` | POST | Undo |
| `/collaboration/sessions/{id}/redo` | POST | Redo |
| `/collaboration/sessions/{id}/locks` | POST | Acquire lock |
| `/collaboration/sessions/{id}/locks/{tid}` | DELETE | Release lock |
| `/collaboration/sessions/{id}/locks` | GET | Get locks |
| `/collaboration/sessions/{id}/chat` | POST | Send chat |
| `/collaboration/sessions/{id}/chat` | GET | Get messages |
| `/collaboration/sessions/{id}/comments` | POST | Add comment |
| `/collaboration/sessions/{id}/comments` | GET | Get comments |
| `/collaboration/sessions/{id}/invites` | POST | Invite user |
| `/collaboration/sessions/{id}/activity` | GET | Get activity |
| `/collaboration/ws/{id}` | WS | WebSocket |


---

## 06-studio/component-visual.md

# Component Visual - Rich Cards

FlowMason Studio provides rich visual representations of components for building interactive pipeline editors.

## Overview

The Component Visual API provides:

- **Rich Cards**: Visual component cards with icons, colors, and badges
- **Port Visualization**: Input/output port definitions for connections
- **Categories & Themes**: Consistent visual categorization
- **Component Palette**: Organized component browser with groups
- **Pipeline Visualization**: Complete visual representation of pipelines
- **Favorites & Recent**: Quick access to commonly used components

## Quick Start

### Get All Component Visuals

```http
GET /api/v1/component-visual/components
```

**Response:**
```json
[
  {
    "component_type": "generator",
    "name": "Generator",
    "description": "Generate text content using LLM",
    "category": "ai",
    "theme": {
      "primary_color": "#8b5cf6",
      "secondary_color": "#a78bfa",
      "icon": "sparkles",
      "icon_color": "#ffffff",
      "gradient": "linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)"
    },
    "ports": [
      {
        "id": "input",
        "name": "Input",
        "direction": "input",
        "type": "any",
        "required": true
      },
      {
        "id": "prompt",
        "name": "Prompt",
        "direction": "input",
        "type": "string",
        "required": true
      },
      {
        "id": "output",
        "name": "Output",
        "direction": "output",
        "type": "any"
      }
    ],
    "badges": [
      {
        "id": "llm",
        "label": "LLM",
        "color": "primary",
        "icon": "sparkles",
        "tooltip": "Uses language model"
      }
    ],
    "capabilities": [
      {
        "id": "llm",
        "name": "LLM Integration",
        "description": "Uses language model",
        "level": "advanced"
      },
      {
        "id": "streaming",
        "name": "Streaming",
        "description": "Supports streaming output",
        "level": "standard"
      }
    ],
    "tags": ["ai", "llm", "text", "generation"],
    "usage_count": 42,
    "popularity_score": 0.42
  }
]
```

### Filter by Category

```http
GET /api/v1/component-visual/components?category=ai
```

Categories:
- `ai` - LLM-powered components
- `data` - Data processing components
- `integration` - External service integrations
- `control` - Control flow components
- `utility` - Helper components
- `custom` - User-defined components

## Component Palette

### Get the Full Palette

```http
GET /api/v1/component-visual/palette
```

**Response:**
```json
{
  "groups": [
    {
      "id": "ai",
      "name": "AI Components",
      "description": "LLM-powered components for generation and evaluation",
      "icon": "sparkles",
      "color": "#8b5cf6",
      "components": ["generator", "critic", "improver", "synthesizer", "selector"],
      "order": 1
    },
    {
      "id": "data",
      "name": "Data Processing",
      "description": "Transform and validate data",
      "icon": "database",
      "color": "#3b82f6",
      "components": ["filter", "json_transform", "schema_validate", "variable_set"],
      "order": 2
    },
    {
      "id": "integration",
      "name": "Integrations",
      "description": "Connect to external services",
      "icon": "plug",
      "color": "#10b981",
      "components": ["http_request", "webhook"],
      "order": 3
    },
    {
      "id": "control",
      "name": "Control Flow",
      "description": "Manage execution flow",
      "icon": "git-branch",
      "color": "#f59e0b",
      "components": ["loop", "foreach", "conditional", "parallel", "output_router"],
      "order": 4
    }
  ],
  "recently_used": ["generator", "filter", "json_transform"],
  "favorites": ["generator", "http_request"]
}
```

### Get Specific Group

```http
GET /api/v1/component-visual/palette/groups/ai
```

## Favorites & Recently Used

### Get Favorites

```http
GET /api/v1/component-visual/favorites
```

### Add to Favorites

```http
POST /api/v1/component-visual/favorites/generator
```

### Remove from Favorites

```http
DELETE /api/v1/component-visual/favorites/generator
```

### Update All Favorites

```http
PUT /api/v1/component-visual/favorites
Content-Type: application/json

{
  "favorites": ["generator", "filter", "http_request"]
}
```

### Get Recently Used

```http
GET /api/v1/component-visual/recent?limit=10
```

### Record Usage

```http
POST /api/v1/component-visual/recent/generator
```

## Port Definitions

Each component has input and output ports for visual connections:

```json
{
  "ports": [
    {
      "id": "input",
      "name": "Input",
      "direction": "input",
      "type": "any",
      "description": "Main input data",
      "required": true,
      "multiple": false
    },
    {
      "id": "output",
      "name": "Output",
      "direction": "output",
      "type": "any",
      "description": "Stage output data"
    }
  ]
}
```

### Port Types

| Type | Description |
|------|-------------|
| `string` | Text data |
| `number` | Numeric data |
| `boolean` | True/false |
| `object` | JSON object |
| `array` | JSON array |
| `any` | Any data type |

### Special Ports

Some components have multiple output ports:

**Filter:**
```json
[
  {"id": "filtered", "name": "Filtered", "direction": "output"},
  {"id": "excluded", "name": "Excluded", "direction": "output"}
]
```

**Conditional:**
```json
[
  {"id": "true_branch", "name": "True", "direction": "output"},
  {"id": "false_branch", "name": "False", "direction": "output"}
]
```

## Badges

Badges indicate component status and capabilities:

```json
{
  "badges": [
    {
      "id": "llm",
      "label": "LLM",
      "color": "primary",
      "icon": "sparkles",
      "tooltip": "Uses language model"
    },
    {
      "id": "favorite",
      "label": "Favorite",
      "color": "danger",
      "icon": "heart"
    }
  ]
}
```

### Badge Colors

- `primary` - Primary brand color
- `success` - Green, positive status
- `warning` - Yellow, caution
- `danger` - Red, important/favorite
- `info` - Blue, informational
- `gray` - Neutral

## Themes

Each category has a consistent visual theme:

| Category | Primary Color | Icon |
|----------|---------------|------|
| AI | `#8b5cf6` | sparkles |
| Data | `#3b82f6` | database |
| Integration | `#10b981` | plug |
| Control | `#f59e0b` | git-branch |
| Utility | `#6b7280` | wrench |
| Custom | `#ec4899` | puzzle-piece |

## Pipeline Visualization

### Get Pipeline Visual

```http
GET /api/v1/component-visual/pipelines/{pipeline_id}?include_execution_state=true
```

**Response:**
```json
{
  "pipeline_id": "my-pipeline",
  "name": "My Pipeline",
  "stages": [
    {
      "stage_id": "generator_1",
      "component": {
        "component_type": "generator",
        "name": "Generator",
        "theme": {...}
      },
      "position": {"x": 100, "y": 100},
      "size": {"width": 250, "height": 150},
      "collapsed": false,
      "status": "completed",
      "progress": 1.0
    },
    {
      "stage_id": "filter_1",
      "component": {...},
      "position": {"x": 450, "y": 100},
      "status": "running",
      "progress": 0.5
    }
  ],
  "connections": [
    {
      "id": "generator_1->filter_1",
      "source_stage": "generator_1",
      "source_port": "output",
      "target_stage": "filter_1",
      "target_port": "input",
      "style": {
        "type": "bezier",
        "color": "#94a3b8",
        "width": 2,
        "animated": true
      }
    }
  ],
  "viewport": {"x": 0, "y": 0, "zoom": 1.0},
  "grid_enabled": true,
  "snap_to_grid": true,
  "grid_size": 20
}
```

### Update Stage Position

```http
PUT /api/v1/component-visual/pipelines/{pipeline_id}/stages/{stage_id}/position
Content-Type: application/json

{
  "x": 200,
  "y": 150
}
```

### Update Viewport

```http
PUT /api/v1/component-visual/pipelines/{pipeline_id}/viewport
Content-Type: application/json

{
  "x": 100,
  "y": 50,
  "zoom": 1.5
}
```

## Connection Styles

### Get Recommended Style

```http
GET /api/v1/component-visual/connection-style?source_type=generator&target_type=filter
```

**Response:**
```json
{
  "type": "bezier",
  "color": "#8b5cf6",
  "width": 2,
  "animated": true,
  "dashed": false
}
```

### Connection Types

- `bezier` - Smooth curved lines (default)
- `straight` - Direct lines
- `step` - Right-angle steps
- `smoothstep` - Rounded right-angle steps

## Search Components

```http
GET /api/v1/component-visual/search?q=filter&limit=10
```

Searches component names, descriptions, and tags.

## Categories API

### List Categories

```http
GET /api/v1/component-visual/categories
```

**Response:**
```json
[
  {
    "category": "ai",
    "name": "AI Components",
    "description": "LLM-powered components for generation and evaluation",
    "color": "#8b5cf6",
    "icon": "sparkles",
    "component_count": 5
  }
]
```

## Frontend Integration

### React Example

```tsx
import { useState, useEffect } from 'react';

interface ComponentVisual {
  component_type: string;
  name: string;
  theme: {
    primary_color: string;
    icon: string;
  };
  ports: Port[];
  badges: Badge[];
}

function ComponentCard({ component }: { component: ComponentVisual }) {
  return (
    <div
      className="component-card"
      style={{
        borderColor: component.theme.primary_color,
        background: component.theme.gradient
      }}
    >
      <div className="component-header">
        <span className="icon">{component.theme.icon}</span>
        <span className="name">{component.name}</span>
      </div>

      <div className="badges">
        {component.badges.map(badge => (
          <span
            key={badge.id}
            className={`badge badge-${badge.color}`}
            title={badge.tooltip}
          >
            {badge.label}
          </span>
        ))}
      </div>

      <div className="ports">
        <div className="inputs">
          {component.ports
            .filter(p => p.direction === 'input')
            .map(port => (
              <div key={port.id} className="port input">
                {port.name}
              </div>
            ))}
        </div>
        <div className="outputs">
          {component.ports
            .filter(p => p.direction === 'output')
            .map(port => (
              <div key={port.id} className="port output">
                {port.name}
              </div>
            ))}
        </div>
      </div>
    </div>
  );
}

function ComponentPalette() {
  const [palette, setPalette] = useState(null);

  useEffect(() => {
    fetch('/api/v1/component-visual/palette')
      .then(res => res.json())
      .then(setPalette);
  }, []);

  if (!palette) return <div>Loading...</div>;

  return (
    <div className="palette">
      {palette.groups.map(group => (
        <div key={group.id} className="group">
          <h3 style={{ color: group.color }}>
            {group.icon} {group.name}
          </h3>
          <div className="components">
            {group.components.map(type => (
              <ComponentCard
                key={type}
                component={/* fetch visual */}
              />
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}
```

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/component-visual/components` | GET | List all component visuals |
| `/component-visual/components/{type}` | GET | Get specific component visual |
| `/component-visual/palette` | GET | Get component palette |
| `/component-visual/palette/groups` | GET | List all groups |
| `/component-visual/palette/groups/{id}` | GET | Get specific group |
| `/component-visual/favorites` | GET | Get favorites |
| `/component-visual/favorites` | PUT | Update all favorites |
| `/component-visual/favorites/{type}` | POST | Add to favorites |
| `/component-visual/favorites/{type}` | DELETE | Remove from favorites |
| `/component-visual/recent` | GET | Get recently used |
| `/component-visual/recent/{type}` | POST | Record usage |
| `/component-visual/pipelines/{id}` | GET | Get pipeline visual |
| `/component-visual/pipelines/{id}/stages/{sid}/position` | PUT | Update position |
| `/component-visual/pipelines/{id}/viewport` | PUT | Update viewport |
| `/component-visual/connection-style` | GET | Get connection style |
| `/component-visual/categories` | GET | List categories |
| `/component-visual/search` | GET | Search components |


---

## 06-studio/debugging.md

# Pipeline Debugging

FlowMason provides a full-featured debugger for stepping through pipeline execution, setting breakpoints, and inspecting stage inputs/outputs.

## Overview

The debugger supports:
- **Breakpoints** - Pause execution before specific stages
- **Stepping** - Execute one stage at a time
- **Pause/Resume** - Stop and continue execution on demand
- **Variable Inspection** - View stage inputs, outputs, and config
- **Exception Breakpoints** - Pause on specific error types
- **WebSocket Events** - Real-time debug updates

## VSCode Integration

The FlowMason VSCode extension provides a native debugging experience using the Debug Adapter Protocol (DAP).

### Starting a Debug Session

1. Open a `.pipeline.json` file
2. Set breakpoints by clicking in the gutter (left margin)
3. Press `F5` or use `Run > Start Debugging`
4. Select "FlowMason" as the debugger

### Debug Controls

| Action | Shortcut | Description |
|--------|----------|-------------|
| Continue | F5 | Resume execution until next breakpoint |
| Step Over | F10 | Execute one stage then pause |
| Pause | F6 | Pause running execution |
| Stop | Shift+F5 | Stop execution entirely |

### Setting Breakpoints

Click in the gutter next to any stage's `"id"` line to set a breakpoint. When execution reaches that stage, it will pause.

```json
{
  "stages": [
    {
      "id": "fetch-data",  // ← Click here to set breakpoint
      "component_type": "http_request",
      "config": { ... }
    }
  ]
}
```

### Viewing Variables

When paused, the Variables pane shows:
- **Input** - Data passed to the current stage
- **Output** - Result from the stage (after completion)
- **Config** - Stage configuration

### Call Stack

The Call Stack shows:
- Current stage at the top
- Completed stages below (execution history)

## Debug Launch Configuration

Create a `.vscode/launch.json` file for custom debug configurations:

```json
{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug Pipeline",
      "pipeline": "${file}",
      "input": {
        "query": "test input"
      },
      "stopOnEntry": false
    },
    {
      "type": "flowmason",
      "request": "launch",
      "name": "Debug with Input File",
      "pipeline": "${workspaceFolder}/pipelines/my-pipeline.pipeline.json",
      "inputFile": "${workspaceFolder}/inputs/test-input.json",
      "stopOnEntry": true
    }
  ]
}
```

### Launch Configuration Options

| Option | Type | Description |
|--------|------|-------------|
| `pipeline` | string | Path to pipeline file (required) |
| `input` | object | Input data for the pipeline |
| `inputFile` | string | Path to JSON file with input data |
| `stopOnEntry` | boolean | Pause before first stage (default: false) |

## Exception Breakpoints

Configure the debugger to pause on specific error types:

1. Open the Breakpoints pane in VSCode
2. Enable exception filters:
   - **All Errors** - Pause on any error
   - **Uncaught Errors** - Pause on unhandled errors
   - **Error Severity** - Pause on ERROR level
   - **Timeout Errors** - Pause on timeouts
   - **Validation Errors** - Pause on validation failures
   - **Connectivity Errors** - Pause on network errors

When an exception is caught, the debugger shows:
- Error description
- Error type and severity
- Stack trace (if available)
- Stage context

## API Debugging

You can also control debugging via the REST API:

### Start Debug Run

```bash
curl -X POST http://localhost:8999/api/v1/debug/run \
  -H "Content-Type: application/json" \
  -d '{
    "pipeline": {
      "name": "test-pipeline",
      "stages": [...]
    },
    "inputs": {"key": "value"},
    "breakpoints": ["stage-1", "stage-3"],
    "stop_on_entry": false
  }'
```

### Pause Execution

```bash
curl -X POST http://localhost:8999/api/v1/runs/{run_id}/debug/pause
```

### Resume Execution

```bash
curl -X POST http://localhost:8999/api/v1/runs/{run_id}/debug/resume
```

### Step to Next Stage

```bash
curl -X POST http://localhost:8999/api/v1/runs/{run_id}/debug/step
```

### Stop Execution

```bash
curl -X POST http://localhost:8999/api/v1/runs/{run_id}/debug/stop
```

### Set Breakpoints

```bash
curl -X PUT http://localhost:8999/api/v1/runs/{run_id}/debug/breakpoints \
  -H "Content-Type: application/json" \
  -d '{"stage_ids": ["stage-1", "stage-3"]}'
```

### Set Exception Breakpoints

```bash
curl -X PUT http://localhost:8999/api/v1/runs/{run_id}/debug/exception-breakpoints \
  -H "Content-Type: application/json" \
  -d '{"filters": ["all", "timeout"]}'
```

### Get Debug State

```bash
curl http://localhost:8999/api/v1/runs/{run_id}/debug/state
```

Response:
```json
{
  "run_id": "abc123",
  "mode": "paused",
  "breakpoints": ["stage-1", "stage-3"],
  "exception_breakpoints": ["all"],
  "current_stage_id": "stage-1",
  "paused_at": "2024-01-15T10:30:00Z",
  "timeout_at": "2024-01-15T10:35:00Z",
  "pause_reason": "breakpoint"
}
```

### Get Exception Info

```bash
curl http://localhost:8999/api/v1/runs/{run_id}/debug/exception-info
```

## WebSocket Debug Events

Connect to the WebSocket endpoint for real-time debug events:

```javascript
const ws = new WebSocket('ws://localhost:8999/api/v1/ws/runs');

// Subscribe to run updates
ws.send(JSON.stringify({
  type: 'subscribe',
  run_id: 'your-run-id'
}));

// Debug commands via WebSocket
ws.send(JSON.stringify({ type: 'pause', run_id: 'your-run-id' }));
ws.send(JSON.stringify({ type: 'resume', run_id: 'your-run-id' }));
ws.send(JSON.stringify({ type: 'step', run_id: 'your-run-id' }));
ws.send(JSON.stringify({ type: 'stop', run_id: 'your-run-id' }));
```

### Event Types

| Event | Description |
|-------|-------------|
| `run_started` | Pipeline execution started |
| `stage_started` | Stage execution began |
| `stage_completed` | Stage finished successfully |
| `stage_failed` | Stage encountered an error |
| `execution_paused` | Execution paused (breakpoint or manual) |
| `execution_resumed` | Execution resumed |
| `run_completed` | Pipeline finished successfully |
| `run_failed` | Pipeline failed |
| `stream_start` | LLM streaming started |
| `token_chunk` | LLM token received |
| `stream_end` | LLM streaming completed |

## Debug Modes

| Mode | Description |
|------|-------------|
| `running` | Normal execution |
| `paused` | Execution paused (breakpoint, manual, or exception) |
| `stepping` | Step mode - pause after each stage |
| `stopped` | Execution terminated |

## Auto-Resume Timeout

To prevent indefinite pauses, the debugger automatically resumes after 5 minutes (configurable). This prevents resource leaks if a debug session is abandoned.

## Advanced: Prompt Editing

During a pause, you can modify LLM prompts before execution:

```bash
# Get current prompt
curl http://localhost:8999/api/v1/runs/{run_id}/debug/stage/{stage_id}/prompt

# Update prompt and rerun
curl -X POST http://localhost:8999/api/v1/runs/{run_id}/debug/stage/{stage_id}/rerun \
  -H "Content-Type: application/json" \
  -d '{"modified_prompt": "Updated prompt text..."}'
```

This is useful for iteratively testing LLM prompts without restarting the entire pipeline.

## Best Practices

1. **Use breakpoints strategically** - Set them before stages you want to inspect
2. **Check stage outputs** - Verify data is being transformed correctly
3. **Watch for exceptions** - Enable exception breakpoints during development
4. **Use step mode for complex flows** - Step through conditional logic
5. **Don't forget to resume** - The auto-timeout prevents runaway pauses

---

# Time Travel Debugging

FlowMason Studio provides time travel debugging capabilities that let you navigate through execution history, inspect state at any point, and replay with modified inputs.

## Time Travel Overview

Time travel debugging enables:

- **Execution Timeline**: Navigate through every stage of a pipeline run
- **State Inspection**: View inputs, outputs, and variables at any point
- **Step Back/Forward**: Move through execution history like a debugger
- **Replay**: Re-run from any snapshot with original or modified inputs
- **What-If Analysis**: Test alternative inputs without restarting from scratch
- **State Diffs**: See exactly what changed between any two points

## Execution Timeline

Get the complete execution timeline for a run:

```http
GET /api/v1/debug/time-travel/runs/{run_id}/timeline
```

**Response:**
```json
{
  "timeline": {
    "run_id": "run_abc123",
    "pipeline_id": "pipe_xyz",
    "total_snapshots": 8,
    "total_duration_ms": 4500,
    "status": "completed",
    "entries": [
      {
        "snapshot_id": "snap_001",
        "stage_id": "stage_input",
        "stage_name": "Parse Input",
        "component_type": "json_transform",
        "snapshot_type": "stage_complete",
        "timestamp": "2024-01-15T10:30:00Z",
        "duration_ms": 150,
        "status": "completed",
        "is_current": false,
        "has_outputs": true,
        "output_preview": "{\"parsed\": true, \"data\": ...}"
      }
    ],
    "current_index": 1,
    "can_step_back": true,
    "can_step_forward": false
  }
}
```

## Viewing Snapshots

### Get Snapshot Details

```http
GET /api/v1/debug/time-travel/snapshots/{snapshot_id}
```

Returns complete state including:
- `pipeline_inputs` - Original pipeline inputs
- `stage_inputs` - Inputs passed to this stage
- `stage_outputs` - Outputs from this stage
- `accumulated_outputs` - All outputs up to this point
- `variables` - Pipeline variables
- `completed_stages` - Stages executed so far
- `pending_stages` - Stages remaining

### Snapshot Types

| Type | Description |
|------|-------------|
| `stage_start` | Captured before a stage executes |
| `stage_complete` | Captured after successful execution |
| `stage_failed` | Captured when a stage fails |
| `checkpoint` | Manual checkpoint |
| `branch_point` | Where execution branched |

## Navigation Commands

### Step Back

```http
GET /api/v1/debug/time-travel/runs/{run_id}/step-back?from_snapshot={snapshot_id}
```

### Step Forward

```http
GET /api/v1/debug/time-travel/runs/{run_id}/step-forward?from_snapshot={snapshot_id}
```

### Jump to Snapshot

```http
POST /api/v1/debug/time-travel/jump
Content-Type: application/json

{
  "snapshot_id": "snap_003",
  "restore_state": true
}
```

## State Comparison

### Compare Any Two Points

```http
GET /api/v1/debug/time-travel/diff?from_snapshot=snap_001&to_snapshot=snap_003
```

**Response:**
```json
{
  "diff": {
    "from_snapshot_id": "snap_001",
    "to_snapshot_id": "snap_003",
    "added_outputs": {
      "stage_llm": {"summary": "This is a greeting..."}
    },
    "modified_outputs": {},
    "removed_outputs": [],
    "added_variables": {"iteration_count": 1},
    "modified_variables": {},
    "stages_completed": ["stage_llm"],
    "duration_ms": 2100,
    "tokens_used": 450
  }
}
```

### See What a Stage Changed

```http
GET /api/v1/debug/time-travel/runs/{run_id}/diff/{stage_id}
```

## Replay Execution

### Replay from a Point

Re-execute the pipeline from any snapshot:

```http
POST /api/v1/debug/time-travel/replay
Content-Type: application/json

{
  "snapshot_id": "snap_002",
  "modified_inputs": null,
  "debug_mode": false
}
```

### Replay with Modified Inputs

```http
POST /api/v1/debug/time-travel/replay
Content-Type: application/json

{
  "snapshot_id": "snap_002",
  "modified_inputs": {
    "text": "Different input"
  },
  "debug_mode": true
}
```

## What-If Analysis

Test alternative scenarios without starting from scratch:

```http
POST /api/v1/debug/time-travel/whatif
Content-Type: application/json

{
  "snapshot_id": "snap_001",
  "modifications": {
    "text": "Different input text",
    "var:temperature": 0.8
  },
  "compare_with_original": true
}
```

### Modification Syntax

- Regular keys modify pipeline inputs: `"input_key": "new_value"`
- Variables use `var:` prefix: `"var:my_variable": "new_value"`

## Python Integration

```python
from flowmason_studio.services.time_travel_storage import get_time_travel_storage

storage = get_time_travel_storage()

# Get execution timeline
timeline = storage.get_timeline("run_abc123")
print(f"Total snapshots: {timeline.total_snapshots}")

# Get specific snapshot
snapshot = storage.get_snapshot("snap_001")
print(f"Inputs: {snapshot.stage_inputs}")
print(f"Outputs: {snapshot.stage_outputs}")

# Compare two points
diff = storage.get_diff("snap_001", "snap_003")
print(f"Added outputs: {list(diff.added_outputs.keys())}")

# Create replay
result = storage.create_replay_run(
    original_run_id="run_abc123",
    from_snapshot_id="snap_002",
    modifications={"input_text": "Modified input"},
)
print(f"Replay started: {result.replay_run_id}")
```

## Cleanup

### Delete Snapshots for a Run

```http
DELETE /api/v1/debug/time-travel/runs/{run_id}/snapshots
```

### Clean Up Old Snapshots

```http
POST /api/v1/debug/time-travel/cleanup?days=7
```

## Time Travel API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/debug/time-travel/runs/{run_id}/timeline` | GET | Get execution timeline |
| `/debug/time-travel/runs/{run_id}/snapshots` | GET | List all snapshots |
| `/debug/time-travel/snapshots/{snapshot_id}` | GET | Get specific snapshot |
| `/debug/time-travel/runs/{run_id}/stages/{stage_id}/snapshot` | GET | Get stage snapshot |
| `/debug/time-travel/diff` | GET | Compare two snapshots |
| `/debug/time-travel/runs/{run_id}/diff/{stage_id}` | GET | Get stage diff |
| `/debug/time-travel/replay` | POST | Start replay |
| `/debug/time-travel/replay/{replay_id}` | GET | Get replay status |
| `/debug/time-travel/whatif` | POST | Start what-if analysis |
| `/debug/time-travel/jump` | POST | Jump to snapshot |
| `/debug/time-travel/runs/{run_id}/step-back` | GET | Step back |
| `/debug/time-travel/runs/{run_id}/step-forward` | GET | Step forward |
| `/debug/time-travel/runs/{run_id}/snapshots` | DELETE | Delete run snapshots |
| `/debug/time-travel/cleanup` | POST | Clean old snapshots |


---

## 06-studio/event-triggers.md

# Event-Driven Triggers

FlowMason supports event-driven pipeline triggers that automatically execute pipelines in response to various events.

## Overview

Event triggers enable automated pipeline execution based on:
- **File System Events**: Watch for file changes
- **Pipeline Completion**: Chain pipelines together
- **MCP Events**: React to MCP server events
- **Message Queues**: Consume from Redis, RabbitMQ, Kafka, SQS
- **Custom Events**: Internal event emission

## Trigger Types

### File Watch Triggers

Monitor file system changes and trigger pipelines when files are created, modified, or deleted.

```json
{
  "name": "Process New CSV Files",
  "pipeline_id": "pipe_data_import",
  "trigger_type": "file_watch",
  "config": {
    "path": "/data/incoming/*.csv",
    "events": ["created", "modified"],
    "recursive": true,
    "debounce_seconds": 5,
    "ignore_patterns": ["*.tmp", "*.part"]
  },
  "default_inputs": {
    "mode": "batch"
  }
}
```

**Configuration Options:**

| Option | Type | Description |
|--------|------|-------------|
| `path` | string | Glob pattern for files to watch |
| `events` | array | Events to trigger on: `created`, `modified`, `deleted`, `moved` |
| `recursive` | boolean | Watch subdirectories (default: true) |
| `debounce_seconds` | number | Debounce rapid file changes |
| `ignore_patterns` | array | Glob patterns to ignore |

**Input Mapping:**
```json
{
  "input_mapping": {
    "file_path": "$.path",
    "event_type": "$.event"
  }
}
```

### Pipeline Completion Triggers

Chain pipelines by triggering one pipeline when another completes.

```json
{
  "name": "Post-Process Data",
  "pipeline_id": "pipe_post_process",
  "trigger_type": "pipeline_completed",
  "config": {
    "source_pipeline_id": "pipe_data_fetch",
    "status": "success",
    "pass_outputs": true,
    "output_mapping": {
      "raw_data": "processed_data"
    }
  }
}
```

**Configuration Options:**

| Option | Type | Description |
|--------|------|-------------|
| `source_pipeline_id` | string | Pipeline to watch |
| `status` | string | Trigger on: `success`, `failed`, `any` |
| `pass_outputs` | boolean | Pass source outputs as inputs |
| `output_mapping` | object | Map source outputs to target inputs |

### MCP Event Triggers

React to events from MCP servers.

```json
{
  "name": "Process New Orders",
  "pipeline_id": "pipe_order_processor",
  "trigger_type": "mcp_event",
  "config": {
    "server_name": "database",
    "event_type": "row_inserted",
    "filter": {
      "table": "orders",
      "status": "pending"
    },
    "input_mapping": {
      "order_id": "$.id",
      "customer": "$.customer_id"
    }
  }
}
```

**Configuration Options:**

| Option | Type | Description |
|--------|------|-------------|
| `server_name` | string | MCP server name |
| `event_type` | string | Event type to listen for |
| `filter` | object | Filter criteria for events |
| `input_mapping` | object | Map event data to inputs |

### Message Queue Triggers

Consume messages from external queues.

```json
{
  "name": "Process Queue Messages",
  "pipeline_id": "pipe_message_handler",
  "trigger_type": "message_queue",
  "config": {
    "queue_type": "redis",
    "connection_url": "redis://localhost:6379",
    "queue_name": "jobs:pending",
    "ack_mode": "auto",
    "batch_size": 1,
    "input_mapping": {
      "payload": "$.body"
    }
  }
}
```

**Supported Queue Types:**
- `redis`: Redis pub/sub and lists
- `rabbitmq`: RabbitMQ AMQP
- `kafka`: Apache Kafka
- `sqs`: AWS SQS

### Custom Event Triggers

React to internal events emitted via API.

```json
{
  "name": "Handle User Events",
  "pipeline_id": "pipe_user_handler",
  "trigger_type": "custom",
  "config": {
    "endpoint": "user_events",
    "filter": {
      "action": "signup"
    },
    "input_mapping": {
      "user_id": "$.user.id",
      "email": "$.user.email"
    }
  }
}
```

## API Reference

### List Triggers

```http
GET /api/v1/triggers
GET /api/v1/triggers?pipeline_id=pipe_abc&enabled_only=true
GET /api/v1/triggers/pipeline/{pipeline_id}
GET /api/v1/triggers/type/{trigger_type}
```

### Create Trigger

```http
POST /api/v1/triggers
Content-Type: application/json

{
  "name": "My Trigger",
  "pipeline_id": "pipe_abc123",
  "trigger_type": "file_watch",
  "config": {
    "path": "/data/*.json",
    "events": ["created"]
  },
  "enabled": true,
  "max_concurrent": 3,
  "cooldown_seconds": 10,
  "default_inputs": {}
}
```

### Update Trigger

```http
PUT /api/v1/triggers/{trigger_id}
Content-Type: application/json

{
  "name": "Updated Name",
  "enabled": false
}
```

### Delete Trigger

```http
DELETE /api/v1/triggers/{trigger_id}
```

### Control Triggers

```http
POST /api/v1/triggers/{trigger_id}/pause
POST /api/v1/triggers/{trigger_id}/resume
POST /api/v1/triggers/{trigger_id}/test
```

### List Events

```http
GET /api/v1/triggers/events
GET /api/v1/triggers/{trigger_id}/events
GET /api/v1/triggers/events?status=completed&since=2024-01-01T00:00:00Z
```

### Emit Custom Events

```http
POST /api/v1/triggers/emit
Content-Type: application/json

{
  "endpoint": "user_events",
  "data": {
    "action": "signup",
    "user": {
      "id": "user_123",
      "email": "user@example.com"
    }
  }
}
```

### Get Statistics

```http
GET /api/v1/triggers/stats
```

**Response:**
```json
{
  "total_triggers": 15,
  "active_triggers": 12,
  "paused_triggers": 2,
  "error_triggers": 1,
  "total_events_24h": 1547,
  "successful_events_24h": 1520,
  "failed_events_24h": 27,
  "triggers_by_type": {
    "file_watch": 5,
    "pipeline_completed": 7,
    "custom": 3
  }
}
```

## Trigger Settings

### Concurrency Control

```json
{
  "max_concurrent": 5
}
```

Limits how many executions can run simultaneously from this trigger.

### Cooldown

```json
{
  "cooldown_seconds": 30
}
```

Minimum time between trigger fires. Prevents rapid-fire executions.

### Default Inputs

```json
{
  "default_inputs": {
    "mode": "production",
    "retry_count": 3
  }
}
```

Default inputs merged with event-resolved inputs.

## Input Resolution

Inputs are resolved in order of priority:
1. Event data via `input_mapping`
2. Default inputs from trigger config
3. Trigger metadata (`_trigger_event`)

### Path Expressions

Input mapping uses JSONPath-like expressions:

```json
{
  "input_mapping": {
    "user_id": "$.data.user.id",
    "items": "$.data.order.items",
    "first_item": "$.data.order.items.0"
  }
}
```

### Trigger Metadata

Every triggered execution receives:

```json
{
  "_trigger_event": {
    "trigger_id": "trig_abc123",
    "event_type": "file_created",
    "timestamp": "2024-01-15T10:30:00Z"
  }
}
```

## Python Integration

### Direct Service Usage

```python
from flowmason_studio.services.trigger_service import get_trigger_service
from flowmason_studio.services.trigger_storage import get_trigger_storage
from flowmason_studio.models.triggers import TriggerType

# Create trigger
storage = get_trigger_storage()
trigger = storage.create_trigger(
    name="Process Files",
    pipeline_id="pipe_processor",
    trigger_type=TriggerType.FILE_WATCH,
    config={
        "path": "/data/*.json",
        "events": ["created"],
    },
)

# Emit custom event
service = get_trigger_service()
await service.emit_custom_event(
    endpoint="my_events",
    event_data={"action": "test", "value": 42},
)

# Notify pipeline completion
await service.notify_pipeline_completed(
    pipeline_id="pipe_source",
    run_id="run_123",
    status="success",
    outputs={"result": "data"},
)
```

## Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `FLOWMASON_TRIGGERS_ENABLED` | `true` | Enable trigger service |

## Error Handling

When a trigger encounters an error:
1. Trigger status changes to `error`
2. Error message is recorded
3. Events continue to be logged

To recover:
```http
POST /api/v1/triggers/{trigger_id}/resume
```

## Best Practices

1. **Use Debouncing**: For file watchers, set appropriate debounce times
2. **Set Cooldowns**: Prevent runaway trigger loops
3. **Limit Concurrency**: Control resource usage with `max_concurrent`
4. **Use Filters**: Filter MCP and custom events to reduce noise
5. **Monitor Events**: Regularly review trigger events for failures
6. **Test Triggers**: Use the test endpoint before enabling

## Troubleshooting

### Trigger Not Firing

1. Check trigger is enabled: `GET /api/v1/triggers/{id}`
2. Verify status is `active`
3. Check cooldown hasn't been triggered
4. Review event filter criteria

### High Event Volume

1. Increase debounce time
2. Add more specific filters
3. Increase cooldown period
4. Review file watch patterns

### Pipeline Not Executing

1. Verify pipeline exists
2. Check trigger events: `GET /api/v1/triggers/{id}/events`
3. Review resolved inputs
4. Check pipeline execution logs


---

## 06-studio/jwt-tokens.md

# Standalone JWT Tokens

FlowMason Studio includes a standalone JWT token service for authentication without external dependencies. This provides flexible token-based authentication with configurable signing and custom claims.

## Overview

Features:
- Configurable signing algorithms (HS256, HS384, HS512)
- Custom claims support
- Access + refresh token pattern
- Token rotation for security
- JTI-based revocation blacklist
- Token introspection

## Quick Start

### Issue Token Pair

```bash
curl -X POST http://localhost:8999/api/v1/tokens/issue \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "user_123",
    "org_id": "org_456",
    "scopes": ["read", "execute"],
    "name": "John Doe",
    "email": "john@example.com"
  }'
```

Response:
```json
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_expires_in": 2592000,
  "scope": "read execute"
}
```

### Use Token

```bash
curl http://localhost:8999/api/v1/pipelines \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
```

## Token Endpoints

### Issue Token Pair

Create both access and refresh tokens:

```bash
curl -X POST http://localhost:8999/api/v1/tokens/issue \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "user_123",
    "org_id": "org_456",
    "scopes": ["read", "write", "execute"],
    "name": "John Doe",
    "email": "john@example.com",
    "custom_claims": {
      "role": "admin",
      "department": "engineering"
    }
  }'
```

### Create Access Token Only

For single-use tokens without refresh capability:

```bash
curl -X POST http://localhost:8999/api/v1/tokens/access \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "service_abc",
    "scopes": ["execute"],
    "expires_in": 300
  }'
```

Response:
```json
{
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "Bearer",
  "expires_in": 300
}
```

### Refresh Tokens

Exchange refresh token for new token pair:

```bash
curl -X POST http://localhost:8999/api/v1/tokens/refresh \
  -d "refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
```

The old refresh token is invalidated (rotation).

### Verify Token

Verify token from Authorization header:

```bash
curl http://localhost:8999/api/v1/tokens/verify \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
```

Response:
```json
{
  "valid": true,
  "claims": {
    "sub": "user_123",
    "org_id": "org_456",
    "scopes": ["read", "execute"],
    "exp": 1705320000,
    "iat": 1705316400
  }
}
```

### Introspect Token

Get token metadata:

```bash
curl -X POST http://localhost:8999/api/v1/tokens/introspect \
  -d "token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
```

Response:
```json
{
  "active": true,
  "sub": "user_123",
  "iss": "flowmason",
  "aud": "flowmason-api",
  "exp": 1705320000,
  "iat": 1705316400,
  "jti": "jti_abc123...",
  "token_type": "access",
  "org_id": "org_456",
  "scope": "read execute"
}
```

### Revoke Token

Revoke by token:
```bash
curl -X POST http://localhost:8999/api/v1/tokens/revoke \
  -d "token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
```

Revoke by JTI:
```bash
curl -X POST http://localhost:8999/api/v1/tokens/revoke/jti_abc123
```

## Token Structure

### Standard Claims

| Claim | Description |
|-------|-------------|
| `sub` | Subject (user or client ID) |
| `iss` | Issuer ("flowmason" by default) |
| `aud` | Audience ("flowmason-api" by default) |
| `exp` | Expiration timestamp |
| `iat` | Issued at timestamp |
| `jti` | JWT ID (unique identifier) |

### Custom Claims

| Claim | Description |
|-------|-------------|
| `org_id` | Organization ID |
| `scopes` | Permission scopes array |
| `token_type` | "access" or "refresh" |
| `name` | User display name |
| `email` | User email |

Add any custom claims via `custom_claims`:

```json
{
  "custom_claims": {
    "role": "admin",
    "team": "platform",
    "features": ["beta", "experimental"]
  }
}
```

## Configuration

### Get Current Config

```bash
curl http://localhost:8999/api/v1/tokens/config
```

Response:
```json
{
  "issuer": "flowmason",
  "audience": "flowmason-api",
  "algorithm": "HS256",
  "access_token_expires_seconds": 3600,
  "refresh_token_expires_seconds": 2592000
}
```

### Update Configuration

```bash
curl -X PATCH http://localhost:8999/api/v1/tokens/config \
  -H "Content-Type: application/json" \
  -d '{
    "issuer": "my-company",
    "access_token_expires_seconds": 1800,
    "algorithm": "HS512"
  }'
```

### Rotate Signing Key

**Warning:** This invalidates ALL existing tokens.

```bash
curl -X POST http://localhost:8999/api/v1/tokens/config/rotate-key
```

## Signing Algorithms

| Algorithm | Type | Key Size |
|-----------|------|----------|
| HS256 | HMAC-SHA256 | 256 bits |
| HS384 | HMAC-SHA384 | 384 bits |
| HS512 | HMAC-SHA512 | 512 bits |

All algorithms use symmetric keys (same key for signing and verification).

## Token Lifetimes

| Token Type | Default Lifetime | Typical Use |
|------------|------------------|-------------|
| Access Token | 1 hour | API authentication |
| Refresh Token | 30 days | Obtaining new access tokens |

Customize via configuration or per-request:

```json
{
  "subject": "user_123",
  "expires_in": 300
}
```

## Security Best Practices

1. **Use HTTPS** in production
2. **Rotate keys periodically** using the rotate-key endpoint
3. **Keep tokens short-lived** - 1 hour or less for access tokens
4. **Implement token rotation** - use refresh flow for long sessions
5. **Revoke tokens** when users log out or on security events
6. **Validate all claims** - check issuer, audience, expiration
7. **Store refresh tokens securely** - never in localStorage
8. **Use appropriate scopes** - principle of least privilege

## Token Revocation

Tokens are revoked by adding their JTI to a blacklist. The blacklist is checked on every token verification.

```bash
# Revoke by token (extracts JTI automatically)
curl -X POST http://localhost:8999/api/v1/tokens/revoke \
  -d "token=..."

# Revoke by JTI directly
curl -X POST http://localhost:8999/api/v1/tokens/revoke/jti_abc123
```

## Debugging

### Decode Token (Without Verification)

For debugging only - does not verify signature:

```bash
curl "http://localhost:8999/api/v1/tokens/decode?token=eyJ0eXAi..."
```

Response:
```json
{
  "payload": {
    "sub": "user_123",
    "exp": 1705320000,
    ...
  },
  "warning": "Signature not verified"
}
```

### Service Statistics

```bash
curl http://localhost:8999/api/v1/tokens/stats
```

Response:
```json
{
  "revoked_token_count": 15,
  "config": {
    "issuer": "flowmason",
    "algorithm": "HS256"
  }
}
```

## Integration Examples

### Python

```python
import httpx

class FlowMasonAuth:
    def __init__(self, base_url: str = "http://localhost:8999"):
        self.base_url = base_url
        self.access_token = None
        self.refresh_token = None

    async def login(self, user_id: str, org_id: str = None):
        """Get tokens for a user."""
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.base_url}/api/v1/tokens/issue",
                json={
                    "subject": user_id,
                    "org_id": org_id,
                    "scopes": ["read", "execute"]
                }
            )
            data = response.json()
            self.access_token = data["access_token"]
            self.refresh_token = data["refresh_token"]
            return data

    async def refresh(self):
        """Refresh tokens."""
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.base_url}/api/v1/tokens/refresh",
                data={"refresh_token": self.refresh_token}
            )
            data = response.json()
            self.access_token = data["access_token"]
            self.refresh_token = data["refresh_token"]
            return data

    def get_headers(self) -> dict:
        """Get authorization headers."""
        return {"Authorization": f"Bearer {self.access_token}"}
```

### JavaScript/Node.js

```javascript
class FlowMasonAuth {
  constructor(baseUrl = 'http://localhost:8999') {
    this.baseUrl = baseUrl;
    this.accessToken = null;
    this.refreshToken = null;
  }

  async login(userId, orgId = null) {
    const response = await fetch(`${this.baseUrl}/api/v1/tokens/issue`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        subject: userId,
        org_id: orgId,
        scopes: ['read', 'execute']
      })
    });
    const data = await response.json();
    this.accessToken = data.access_token;
    this.refreshToken = data.refresh_token;
    return data;
  }

  async refresh() {
    const response = await fetch(`${this.baseUrl}/api/v1/tokens/refresh`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: `refresh_token=${this.refreshToken}`
    });
    const data = await response.json();
    this.accessToken = data.access_token;
    this.refreshToken = data.refresh_token;
    return data;
  }

  getHeaders() {
    return { Authorization: `Bearer ${this.accessToken}` };
  }
}
```

## Comparison with OAuth 2.0

| Feature | JWT Tokens | OAuth 2.0 |
|---------|------------|-----------|
| External Auth | Not needed | Required for auth code flow |
| Client Registration | Not needed | Required |
| Complexity | Simple | More complex |
| Use Case | Internal services | Third-party apps |
| Token Format | JWT | JWT or opaque |

Use JWT tokens for:
- Service-to-service auth
- Internal applications
- Simple authentication needs

Use OAuth 2.0 for:
- Third-party integrations
- User consent flows
- External client management


---

## 06-studio/marketplace.md

# Pipeline Marketplace

FlowMason Studio includes a marketplace for sharing and discovering pipeline templates.

## Overview

The Pipeline Marketplace provides:

- **Discovery**: Browse and search pipeline templates
- **Publishing**: Share your pipelines with the community
- **Reviews**: Rate and review pipelines
- **Collections**: Curated sets of related pipelines
- **Versioning**: Publish new versions with changelogs
- **Installation**: One-click install to your workspace

## Quick Start

### Browse Featured Pipelines

```http
GET /api/v1/marketplace/featured
```

**Response:**
```json
[
  {
    "id": "listing_1",
    "slug": "content-summarizer",
    "name": "Content Summarizer",
    "tagline": "Summarize long articles into concise key points",
    "category": "ai_generation",
    "publisher": {
      "name": "FlowMason Team",
      "verified": true
    },
    "stats": {
      "downloads": 150,
      "average_rating": 4.8
    },
    "pricing": {
      "model": "free"
    },
    "featured": true
  }
]
```

### Search Pipelines

```http
POST /api/v1/marketplace/search
Content-Type: application/json

{
  "query": "summarize",
  "category": "ai_generation",
  "pricing": "free",
  "min_rating": 4.0,
  "sort_by": "downloads",
  "page": 1,
  "per_page": 20
}
```

Or use GET:
```http
GET /api/v1/marketplace/search?query=summarize&category=ai_generation&sort_by=downloads
```

### View Listing Details

```http
GET /api/v1/marketplace/listings/listing_1
```

Or by slug:
```http
GET /api/v1/marketplace/listings/by-slug/content-summarizer
```

**Response:**
```json
{
  "id": "listing_1",
  "slug": "content-summarizer",
  "name": "Content Summarizer",
  "tagline": "Summarize long articles into concise key points",
  "description": "A complete pipeline for summarizing long-form content...",
  "category": "ai_generation",
  "tags": ["summarization", "ai", "content", "nlp"],
  "status": "published",
  "publisher": {
    "id": "pub_flowmason",
    "name": "FlowMason Team",
    "verified": true,
    "total_listings": 5,
    "average_rating": 4.8
  },
  "pipeline_template": {
    "name": "content-summarizer",
    "stages": [...]
  },
  "readme": "# Content Summarizer\n\n...",
  "current_version": "1.0.0",
  "versions": [
    {
      "version": "1.0.0",
      "released_at": "2024-01-15T10:00:00Z",
      "changelog": "Initial release",
      "downloads": 150
    }
  ],
  "pricing": {
    "model": "free"
  },
  "stats": {
    "views": 500,
    "downloads": 150,
    "favorites": 25,
    "reviews": 10,
    "average_rating": 4.8
  }
}
```

## Categories

| Category | Description |
|----------|-------------|
| `ai_generation` | AI-powered content generation |
| `data_processing` | Transform, validate, and clean data |
| `integration` | Connect to external APIs and services |
| `automation` | Automate repetitive tasks |
| `analytics` | Analyze data and generate insights |
| `content` | Content moderation and management |
| `devops` | CI/CD, deployment, infrastructure |
| `other` | Miscellaneous pipelines |

### Get Categories

```http
GET /api/v1/marketplace/categories
```

### Browse by Category

```http
GET /api/v1/marketplace/categories/ai_generation?limit=20
```

## Installation

### Install a Listing

```http
POST /api/v1/marketplace/listings/{listing_id}/install
Content-Type: application/json

{
  "version": "1.0.0",
  "create_pipeline": true,
  "pipeline_name": "My Summarizer",
  "customizations": {
    "model": "gpt-4"
  }
}
```

**Response:**
```json
{
  "id": "install_xyz",
  "listing_id": "listing_1",
  "version": "1.0.0",
  "installed_at": "2024-01-15T12:00:00Z",
  "pipeline_id": "pipe_abc123",
  "customizations": {...}
}
```

### Get My Installations

```http
GET /api/v1/marketplace/installations
```

## Publishing

### Create a Listing

```http
POST /api/v1/marketplace/listings
Content-Type: application/json

{
  "name": "My Pipeline",
  "tagline": "A brief description of what it does",
  "description": "Detailed description of the pipeline...",
  "category": "ai_generation",
  "tags": ["ai", "automation"],
  "pipeline_template": {
    "name": "my-pipeline",
    "stages": [...]
  },
  "pricing": {
    "model": "free"
  },
  "readme": "# My Pipeline\n\n## Usage\n..."
}
```

### Update a Listing

```http
PATCH /api/v1/marketplace/listings/{listing_id}
Content-Type: application/json

{
  "tagline": "Updated tagline",
  "description": "Updated description",
  "tags": ["ai", "automation", "new-tag"]
}
```

### Submit for Review

```http
POST /api/v1/marketplace/listings/{listing_id}/submit
```

### Publish a New Version

```http
POST /api/v1/marketplace/listings/{listing_id}/versions
Content-Type: application/json

{
  "version": "1.1.0",
  "changelog": "Added support for multiple output formats",
  "pipeline_template": {
    "name": "my-pipeline",
    "stages": [...]
  },
  "min_flowmason_version": "0.7.0"
}
```

### Archive a Listing

```http
POST /api/v1/marketplace/listings/{listing_id}/archive
```

## Reviews

### Submit a Review

```http
POST /api/v1/marketplace/listings/{listing_id}/reviews
Content-Type: application/json

{
  "rating": 5,
  "title": "Excellent pipeline!",
  "content": "This pipeline saved me hours of work..."
}
```

### Get Reviews

```http
GET /api/v1/marketplace/listings/{listing_id}/reviews?limit=20&offset=0
```

### Mark Review Helpful

```http
POST /api/v1/marketplace/listings/{listing_id}/reviews/{review_id}/helpful
```

## User Library

### Get My Library

```http
GET /api/v1/marketplace/library
```

**Response:**
```json
{
  "user_id": "user_123",
  "purchased": ["listing_1", "listing_2"],
  "favorites": ["listing_1", "listing_3"],
  "installed": ["listing_1"],
  "recently_viewed": ["listing_1", "listing_4", "listing_5"]
}
```

### Add to Favorites

```http
POST /api/v1/marketplace/library/favorites/{listing_id}
```

### Remove from Favorites

```http
DELETE /api/v1/marketplace/library/favorites/{listing_id}
```

## Collections

Curated sets of related pipelines.

### List Collections

```http
GET /api/v1/marketplace/collections
```

**Response:**
```json
[
  {
    "id": "coll_1",
    "name": "AI Starter Kit",
    "description": "Essential AI pipelines for getting started",
    "slug": "ai-starter-kit",
    "listings": ["listing_1", "listing_2", "listing_3"],
    "curated_by": "user_curator",
    "featured": true
  }
]
```

### Get Collection

```http
GET /api/v1/marketplace/collections/{collection_id}
```

### Create Collection

```http
POST /api/v1/marketplace/collections
Content-Type: application/json

{
  "name": "My Collection",
  "description": "A collection of my favorite pipelines",
  "listing_ids": ["listing_1", "listing_2"]
}
```

### Add to Collection

```http
POST /api/v1/marketplace/collections/{collection_id}/listings/{listing_id}
```

## Publishers

### Get Publisher Profile

```http
GET /api/v1/marketplace/publishers/{publisher_id}
```

**Response:**
```json
{
  "id": "pub_flowmason",
  "name": "FlowMason Team",
  "username": "flowmason",
  "verified": true,
  "member_since": "2024-01-01T00:00:00Z",
  "total_listings": 5,
  "total_downloads": 1000,
  "average_rating": 4.8
}
```

### Get Publisher Listings

```http
GET /api/v1/marketplace/publishers/{publisher_id}/listings
```

## Statistics

### Get Marketplace Stats

```http
GET /api/v1/marketplace/stats
```

**Response:**
```json
{
  "total_listings": 150,
  "total_publishers": 45,
  "total_downloads": 10000,
  "total_reviews": 500,
  "categories": {
    "ai_generation": 45,
    "data_processing": 30,
    "integration": 25,
    "automation": 20,
    "analytics": 15,
    "content": 10,
    "devops": 5
  },
  "trending": ["listing_1", "listing_5", "listing_3"],
  "new_this_week": 12
}
```

## Pricing Models

| Model | Description |
|-------|-------------|
| `free` | Free to use |
| `one_time` | One-time purchase |
| `subscription` | Monthly/yearly subscription |
| `usage_based` | Pay per execution |

## Listing Status

| Status | Description |
|--------|-------------|
| `draft` | Not yet submitted |
| `pending_review` | Awaiting review |
| `published` | Live in marketplace |
| `rejected` | Review rejected |
| `archived` | No longer available |

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/marketplace/featured` | GET | Get featured listings |
| `/marketplace/trending` | GET | Get trending listings |
| `/marketplace/new` | GET | Get newest listings |
| `/marketplace/categories` | GET | List categories |
| `/marketplace/categories/{cat}` | GET | Get category listings |
| `/marketplace/search` | GET/POST | Search listings |
| `/marketplace/listings` | POST | Create listing |
| `/marketplace/listings/{id}` | GET | Get listing |
| `/marketplace/listings/{id}` | PATCH | Update listing |
| `/marketplace/listings/{id}/submit` | POST | Submit for review |
| `/marketplace/listings/{id}/archive` | POST | Archive listing |
| `/marketplace/listings/{id}/versions` | POST | Publish version |
| `/marketplace/listings/{id}/install` | POST | Install listing |
| `/marketplace/listings/{id}/reviews` | GET | Get reviews |
| `/marketplace/listings/{id}/reviews` | POST | Submit review |
| `/marketplace/installations` | GET | Get my installations |
| `/marketplace/library` | GET | Get my library |
| `/marketplace/library/favorites/{id}` | POST | Add favorite |
| `/marketplace/library/favorites/{id}` | DELETE | Remove favorite |
| `/marketplace/collections` | GET | List collections |
| `/marketplace/collections` | POST | Create collection |
| `/marketplace/collections/{id}` | GET | Get collection |
| `/marketplace/publishers/{id}` | GET | Get publisher |
| `/marketplace/publishers/{id}/listings` | GET | Publisher listings |
| `/marketplace/stats` | GET | Get marketplace stats |


---

## 06-studio/mcp-api.md

# Studio MCP API

FlowMason Studio exposes an HTTP API that mirrors MCP (Model Context Protocol) tools, enabling AI assistants to interact with Studio via standard HTTP requests.

## Overview

The MCP API provides:
- **Tool Discovery**: List available MCP tools
- **Tool Execution**: Execute tools via HTTP POST
- **Convenience Endpoints**: Direct access to common operations
- **Pipeline Management**: Create, validate, and query pipelines

## Base URL

```
http://localhost:8999/api/v1/mcp
```

## Endpoints

### List Available Tools

```
GET /api/v1/mcp/tools
```

Returns a list of all available MCP tools with their descriptions and parameters.

**Response:**
```json
[
  {
    "name": "list_pipelines",
    "description": "List all available pipelines in the workspace",
    "parameters": {}
  },
  {
    "name": "suggest_pipeline",
    "description": "Get AI-powered suggestions for building a pipeline",
    "parameters": {
      "task_description": {"type": "string", "required": true}
    }
  }
]
```

### Execute Tool

```
POST /api/v1/mcp/tools/call
```

Execute any MCP tool by name.

**Request:**
```json
{
  "tool_name": "suggest_pipeline",
  "arguments": {
    "task_description": "Summarize articles and filter by sentiment"
  }
}
```

**Response:**
```json
{
  "success": true,
  "content": "## Suggested Pipeline for: Summarize articles...\n\n...",
  "error": null,
  "metadata": {}
}
```

## Convenience Endpoints

### Suggest Pipeline

```
POST /api/v1/mcp/suggest
```

Get pipeline suggestions based on a task description.

**Request:**
```json
{
  "task_description": "Process customer feedback and generate reports"
}
```

**Response:**
```json
{
  "name": "suggested-pipeline",
  "description": "Process customer feedback and generate reports",
  "stages": [
    {
      "component": "generator",
      "purpose": "Generate summary",
      "rationale": "Use LLM to create a summary of the input"
    },
    {
      "component": "filter",
      "purpose": "Filter items based on criteria",
      "rationale": "Filter data to include only relevant items"
    }
  ],
  "example_pipeline": { ... }
}
```

### Generate Stage

```
POST /api/v1/mcp/generate-stage
```

Generate a stage configuration for a component type.

**Request:**
```json
{
  "stage_type": "generator",
  "purpose": "summarize the article content",
  "input_source": "input"
}
```

**Response:**
```json
{
  "id": "generator-a1b2c3",
  "name": "summarize the article content",
  "component_type": "generator",
  "config": {
    "prompt": "Based on the following input, summarize the article content:\n\n{{input}}",
    "max_tokens": 1000,
    "temperature": 0.7
  },
  "depends_on": null
}
```

### Validate Pipeline

```
POST /api/v1/mcp/validate
```

Validate a pipeline configuration.

**Request:**
```json
{
  "pipeline_json": "{\"name\": \"test\", \"stages\": []}"
}
```

**Response:**
```json
{
  "valid": false,
  "errors": ["Pipeline must have at least one stage"],
  "warnings": ["Consider adding a 'description' field"]
}
```

### Create Pipeline

```
POST /api/v1/mcp/create
```

Create a new pipeline.

**Request:**
```json
{
  "name": "my-pipeline",
  "description": "A pipeline that processes data",
  "stages": [
    {
      "id": "process",
      "name": "Process Data",
      "component_type": "generator",
      "config": {
        "prompt": "Process: {{input}}"
      }
    }
  ],
  "input_schema": {
    "type": "object",
    "properties": {
      "text": {"type": "string"}
    }
  }
}
```

**Response:**
```json
{
  "pipeline_id": "pipe_abc123",
  "name": "my-pipeline",
  "path": null,
  "message": "Pipeline created successfully"
}
```

## Available Tools

### list_pipelines
List all pipelines in the workspace.

**Parameters:** None

**Returns:** Formatted list of pipelines with name, version, status, and stage count.

### list_components
List all available FlowMason components.

**Parameters:** None

**Returns:** Components grouped by category with descriptions.

### get_component
Get detailed information about a specific component.

**Parameters:**
- `component_type` (string, required): The component type to look up

**Returns:** Component details including configuration schema.

### suggest_pipeline
Get AI-powered suggestions for building a pipeline.

**Parameters:**
- `task_description` (string, required): Natural language description of desired pipeline

**Returns:** Suggested components with rationale and example structure.

### generate_stage
Generate a stage configuration for a component type.

**Parameters:**
- `stage_type` (string, required): Component type (e.g., "generator", "filter")
- `purpose` (string, required): What the stage should accomplish
- `input_source` (string, default: "input"): Input source reference

**Returns:** Complete stage configuration ready to add to a pipeline.

### validate_pipeline_config
Validate a pipeline configuration.

**Parameters:**
- `pipeline_json` (string, required): Pipeline configuration as JSON string

**Returns:** Validation result with errors and warnings.

### create_pipeline
Create a new pipeline from a configuration.

**Parameters:**
- `name` (string, required): Pipeline name
- `description` (string, required): Pipeline description
- `stages_json` (string, required): JSON array of stage objects
- `input_schema_json` (string, optional): JSON Schema for inputs

**Returns:** Created pipeline ID and confirmation.

## Integration Examples

### Using with curl

```bash
# List available tools
curl http://localhost:8999/api/v1/mcp/tools

# Get pipeline suggestions
curl -X POST http://localhost:8999/api/v1/mcp/suggest \
  -H "Content-Type: application/json" \
  -d '{"task_description": "Summarize articles"}'

# Execute any tool
curl -X POST http://localhost:8999/api/v1/mcp/tools/call \
  -H "Content-Type: application/json" \
  -d '{"tool_name": "list_components", "arguments": {}}'
```

### Using with Python

```python
import requests

BASE_URL = "http://localhost:8999/api/v1/mcp"

# Get suggestions
response = requests.post(
    f"{BASE_URL}/suggest",
    json={"task_description": "Process customer feedback"}
)
suggestions = response.json()

# Generate stage
stage = requests.post(
    f"{BASE_URL}/generate-stage",
    json={
        "stage_type": "generator",
        "purpose": "summarize feedback",
        "input_source": "input"
    }
).json()

# Create pipeline
pipeline = requests.post(
    f"{BASE_URL}/create",
    json={
        "name": "feedback-processor",
        "description": "Processes customer feedback",
        "stages": [stage]
    }
).json()
```

### Using with AI Assistants

The MCP API is designed to be used by AI assistants like Claude. When integrated with an assistant, it enables natural language pipeline creation:

```
User: "Create a pipeline that summarizes articles and filters out sports content"
Assistant: [Uses suggest_pipeline to get recommendations]
         [Generates stages with generate_stage]
         [Validates with validate_pipeline_config]
         [Creates pipeline with create_pipeline]

I have created your "article-summarizer" pipeline with 2 stages:
1. generator - Summarize article content
2. filter - Filter out sports articles

You can run it with: fm run article-summarizer.pipeline.json
```

## Error Handling

All endpoints return standard HTTP status codes:

- `200`: Success
- `400`: Bad request (invalid parameters)
- `404`: Resource not found
- `500`: Internal server error

Error responses include a `detail` field:

```json
{
  "detail": "Invalid pipeline JSON: Expecting value: line 1 column 1"
}
```

## Authentication

When authentication is enabled in Studio, include the JWT token in requests:

```bash
curl -H "Authorization: Bearer <token>" http://localhost:8999/api/v1/mcp/tools
```

## Related Documentation

- [MCP Server (CLI)](../07-integrations/mcp.md) - MCP server for Claude Desktop
- [AI Generation Tools](../07-integrations/mcp-ai-generation.md) - Detailed MCP tool reference
- [VSCode MCP Integration](../07-integrations/vscode-mcp.md) - MCP in VSCode extension



---

## 06-studio/mcp-assistant.md

# MCP AI Assistant

FlowMason Studio includes an AI-powered MCP Assistant that helps discover, understand, and use MCP tools effectively.

## Overview

The MCP Assistant provides:

- **Tool Discovery**: Find the right tools for any task
- **Smart Recommendations**: AI-analyzed tool suggestions with relevance scoring
- **Tool Explanations**: Detailed explanations of tool capabilities and usage
- **Tool Chains**: Automated multi-step workflows
- **Smart Invocation**: AI-assisted parameter resolution
- **Autocomplete**: Intelligent parameter suggestions
- **Conversations**: Multi-turn AI-assisted interactions

## Quick Start

### Analyze a Task

```http
POST /api/v1/mcp-assistant/analyze
Content-Type: application/json

{
  "task": "I need to create a pipeline that processes customer feedback",
  "available_data": {"source": "database"},
  "constraints": ["must handle large volumes"]
}
```

**Response:**
```json
{
  "success": true,
  "message": "Task analyzed successfully",
  "analysis": {
    "task": "I need to create a pipeline that processes customer feedback",
    "intent": "Create automated workflow for customer feedback processing",
    "required_capabilities": ["pipeline_management", "data_processing"],
    "data_requirements": ["customer feedback data", "processing rules"],
    "suggested_workflow": [
      "Create a new pipeline for feedback processing",
      "Configure data input source",
      "Add processing stages",
      "Set up output handling"
    ],
    "tool_recommendations": [
      {
        "tool_name": "create_pipeline",
        "relevance_score": 0.95,
        "reason": "Primary tool for creating new pipelines",
        "suggested_params": {
          "name": "customer-feedback-processor"
        }
      },
      {
        "tool_name": "add_stage",
        "relevance_score": 0.85,
        "reason": "Needed to add processing stages"
      }
    ]
  }
}
```

### Get Tool Recommendations

Quick recommendations without full analysis:

```http
GET /api/v1/mcp-assistant/recommend?task=summarize%20documents&limit=3
```

**Response:**
```json
{
  "task": "summarize documents",
  "recommendations": [
    {
      "tool_name": "run_pipeline",
      "relevance_score": 0.9,
      "reason": "Execute a summarization pipeline"
    },
    {
      "tool_name": "create_pipeline",
      "relevance_score": 0.7,
      "reason": "Create a new summarization pipeline"
    }
  ]
}
```

## Tool Discovery

### List All Tools

```http
GET /api/v1/mcp-assistant/tools
```

Returns enhanced tool information with AI-generated metadata:

```json
[
  {
    "name": "create_pipeline",
    "description": "Create a new pipeline configuration",
    "category": "pipeline",
    "capabilities": [
      {
        "name": "Pipeline Creation",
        "description": "Create new pipeline definitions",
        "examples": ["Create a summarization pipeline"]
      }
    ],
    "when_to_use": [
      "Starting a new workflow",
      "Setting up data processing"
    ],
    "prerequisites": [
      "Know the components you want to use"
    ],
    "related_tools": ["add_stage", "run_pipeline"],
    "usage_examples": [
      {
        "description": "Create a simple pipeline",
        "inputs": {"name": "my-pipeline", "description": "Process data"},
        "output": {"id": "pipe_123", "name": "my-pipeline"}
      }
    ]
  }
]
```

### Filter by Category

```http
GET /api/v1/mcp-assistant/tools?category=pipeline
```

Categories:
- `pipeline` - Pipeline management tools
- `component` - Component operations
- `data` - Data manipulation
- `integration` - External integrations
- `utility` - General utilities

### Search Tools

```http
GET /api/v1/mcp-assistant/tools/search?q=pipeline&limit=5
```

## Tool Explanations

### Get Detailed Explanation

```http
POST /api/v1/mcp-assistant/explain
Content-Type: application/json

{
  "tool_name": "run_pipeline",
  "context": "I'm building a batch processing system",
  "detail_level": "detailed"
}
```

**Response:**
```json
{
  "tool_name": "run_pipeline",
  "summary": "Execute a pipeline with given inputs",
  "detailed_description": "The run_pipeline tool executes a configured pipeline...",
  "parameter_explanations": {
    "pipeline_id": "The unique identifier of the pipeline to run",
    "inputs": "JSON object containing the input data for the pipeline"
  },
  "common_use_cases": [
    "Execute pipelines on demand",
    "Process batch data",
    "Test pipeline configurations"
  ],
  "tips": [
    "Use async execution for long-running pipelines",
    "Monitor execution via WebSocket for real-time updates"
  ],
  "warnings": [
    "Ensure inputs match the pipeline's expected schema"
  ],
  "see_also": ["create_pipeline", "get_pipeline_status"]
}
```

### Quick Explanation

```http
GET /api/v1/mcp-assistant/explain/run_pipeline?detail_level=brief
```

## Tool Chains

Create automated multi-step workflows:

### Create a Chain

```http
POST /api/v1/mcp-assistant/chains
Content-Type: application/json

{
  "goal": "Set up a new content moderation pipeline and run it",
  "max_steps": 5
}
```

**Response:**
```json
{
  "id": "chain_abc123",
  "name": "Content Moderation Setup",
  "description": "Set up a new content moderation pipeline and run it",
  "steps": [
    {
      "order": 1,
      "tool_name": "create_pipeline",
      "description": "Create the content moderation pipeline",
      "parameters": {
        "name": "content-moderation",
        "description": "Moderate user content"
      },
      "output_key": "pipeline"
    },
    {
      "order": 2,
      "tool_name": "add_stage",
      "description": "Add moderation component",
      "input_mapping": {
        "pipeline_id": "pipeline.id"
      },
      "parameters": {
        "component_type": "classifier"
      }
    },
    {
      "order": 3,
      "tool_name": "run_pipeline",
      "description": "Execute the pipeline",
      "input_mapping": {
        "pipeline_id": "pipeline.id"
      }
    }
  ],
  "estimated_duration": "~2 minutes"
}
```

### List Chains

```http
GET /api/v1/mcp-assistant/chains
```

### Get Chain Details

```http
GET /api/v1/mcp-assistant/chains/chain_abc123
```

## Smart Invocation

Let the AI resolve parameters from natural language:

```http
POST /api/v1/mcp-assistant/invoke
Content-Type: application/json

{
  "tool_name": "create_pipeline",
  "natural_language_params": "create a pipeline called news-summarizer for processing RSS feeds",
  "partial_params": {"version": "1.0.0"},
  "context": {"available_components": ["generator", "filter"]}
}
```

**Response:**
```json
{
  "success": true,
  "resolved_params": {
    "name": "news-summarizer",
    "description": "Pipeline for processing RSS feeds",
    "version": "1.0.0"
  },
  "confidence": 0.85,
  "explanations": {
    "name": "Extracted from 'called news-summarizer'",
    "description": "Inferred from 'processing RSS feeds'"
  },
  "warnings": []
}
```

## Autocomplete

Get intelligent parameter suggestions:

```http
POST /api/v1/mcp-assistant/autocomplete
Content-Type: application/json

{
  "tool_name": "run_pipeline",
  "parameter": "pipeline_id",
  "partial_value": "news",
  "context": {"recent_pipelines": ["news-summarizer", "news-classifier"]}
}
```

**Response:**
```json
{
  "parameter": "pipeline_id",
  "suggestions": [
    {
      "value": "news-summarizer",
      "label": "news-summarizer",
      "description": "Recently used pipeline",
      "source": "history"
    },
    {
      "value": "news-classifier",
      "label": "news-classifier",
      "description": "Recently used pipeline",
      "source": "history"
    }
  ]
}
```

## Conversations

For complex multi-step interactions:

### Start a Conversation

```http
POST /api/v1/mcp-assistant/conversations
Content-Type: application/json

{
  "initial_task": "Help me set up a document processing workflow"
}
```

**Response:**
```json
{
  "context": {
    "id": "conv_xyz789",
    "started_at": "2024-01-15T10:30:00Z",
    "messages": [],
    "tools_used": [],
    "current_task": "Help me set up a document processing workflow",
    "accumulated_data": {}
  },
  "assistant_response": "I'll help you with: Help me set up a document processing workflow. Let me analyze what tools we'll need."
}
```

### Continue the Conversation

```http
POST /api/v1/mcp-assistant/conversations/conv_xyz789/messages
Content-Type: application/json

{
  "message": "I want to extract text and summarize it"
}
```

### Get Conversation State

```http
GET /api/v1/mcp-assistant/conversations/conv_xyz789
```

### End Conversation

```http
DELETE /api/v1/mcp-assistant/conversations/conv_xyz789
```

## Categories

List all tool categories:

```http
GET /api/v1/mcp-assistant/categories
```

**Response:**
```json
[
  {
    "category": "pipeline",
    "description": "Tools for creating and managing pipelines",
    "tool_count": 5,
    "example_tools": ["create_pipeline", "run_pipeline", "list_pipelines"]
  },
  {
    "category": "component",
    "description": "Tools for working with components",
    "tool_count": 3,
    "example_tools": ["list_components", "get_component"]
  }
]
```

## Python Integration

```python
import httpx
import asyncio

async def main():
    async with httpx.AsyncClient(base_url="http://localhost:8999/api/v1") as client:
        # Analyze a task
        response = await client.post("/mcp-assistant/analyze", json={
            "task": "Build a sentiment analysis pipeline",
        })
        analysis = response.json()
        print(f"Intent: {analysis['analysis']['intent']}")

        for rec in analysis['analysis']['tool_recommendations']:
            print(f"  - {rec['tool_name']}: {rec['reason']}")

        # Get tool explanation
        response = await client.post("/mcp-assistant/explain", json={
            "tool_name": "create_pipeline",
            "detail_level": "detailed",
        })
        explanation = response.json()
        print(f"\nTool: {explanation['tool_name']}")
        print(f"Summary: {explanation['summary']}")

        # Create a tool chain
        response = await client.post("/mcp-assistant/chains", json={
            "goal": "Create and run a summarization pipeline",
        })
        chain = response.json()
        print(f"\nChain: {chain['name']}")
        for step in chain['steps']:
            print(f"  {step['order']}. {step['tool_name']}: {step['description']}")

asyncio.run(main())
```

## Best Practices

1. **Be Specific**: Provide detailed task descriptions for better recommendations
2. **Include Context**: Pass available data and constraints for accurate analysis
3. **Use Conversations**: For complex multi-step workflows, use the conversation API
4. **Leverage Autocomplete**: Use autocomplete for faster parameter entry
5. **Review Chains**: Always review generated tool chains before execution

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/mcp-assistant/tools` | GET | List all enhanced tools |
| `/mcp-assistant/tools/{name}` | GET | Get specific tool details |
| `/mcp-assistant/tools/search` | GET | Search tools by keyword |
| `/mcp-assistant/analyze` | POST | Analyze task and get recommendations |
| `/mcp-assistant/recommend` | GET | Quick tool recommendations |
| `/mcp-assistant/explain` | POST | Get detailed tool explanation |
| `/mcp-assistant/explain/{name}` | GET | Quick tool explanation |
| `/mcp-assistant/chains` | POST | Create a tool chain |
| `/mcp-assistant/chains` | GET | List all chains |
| `/mcp-assistant/chains/{id}` | GET | Get specific chain |
| `/mcp-assistant/invoke` | POST | Smart tool invocation |
| `/mcp-assistant/autocomplete` | POST | Get parameter suggestions |
| `/mcp-assistant/conversations` | POST | Start conversation |
| `/mcp-assistant/conversations/{id}/messages` | POST | Send message |
| `/mcp-assistant/conversations/{id}` | GET | Get conversation state |
| `/mcp-assistant/conversations/{id}` | DELETE | End conversation |
| `/mcp-assistant/categories` | GET | List tool categories |


---

## 06-studio/mobile-app.md

# Mobile Companion App

Monitor and trigger FlowMason pipelines from your iOS or Android device.

## Overview

```
┌─────────────────────────┐
│  FlowMason Mobile       │
├─────────────────────────┤
│                         │
│  Active Pipelines    ▼  │
│  ┌─────────────────────┐│
│  │ data-processor      ││
│  │ ● Running (45%)     ││
│  │ Started 2m ago      ││
│  └─────────────────────┘│
│  ┌─────────────────────┐│
│  │ daily-report        ││
│  │ ○ Scheduled 6:00 AM ││
│  │ Last: Success       ││
│  └─────────────────────┘│
│                         │
│  Quick Actions          │
│  ┌────┐ ┌────┐ ┌────┐  │
│  │Run │ │Stop│ │View│  │
│  └────┘ └────┘ └────┘  │
│                         │
│  [📊 Dashboard]         │
└─────────────────────────┘
```

## Installation

### iOS

Download from the App Store (coming soon) or build from source:

```bash
cd mobile/flowmason-mobile
npm install
npx expo run:ios
```

### Android

Download from Google Play (coming soon) or build from source:

```bash
cd mobile/flowmason-mobile
npm install
npx expo run:android
```

### Development

```bash
# Install dependencies
npm install

# Start Expo dev server
npm start

# Scan QR code with Expo Go app
```

## Features

### Dashboard

The dashboard shows:
- **Active Pipelines**: Currently running executions
- **Pipeline Stats**: Success rate, total runs, failures
- **Recent Activity**: Latest execution events
- **Quick Actions**: Run, stop, view most-used pipelines

### Pipeline Management

Browse and manage your pipelines:
- View all pipelines in your organization
- Filter by status (running, scheduled, idle)
- Search by name or tag
- Favorite frequently used pipelines

### Run History

View execution history:
- Filter by date range
- Filter by status (success, failed, running)
- View execution details and logs
- Compare run durations

### Settings

Configure the app:
- Server URL
- API key (stored securely)
- Push notifications
- Theme preferences

## Configuration

### Connecting to Studio

1. Open the Settings screen
2. Enter your FlowMason Studio URL
3. Enter your API key
4. Tap "Test Connection"
5. Save settings

```
Server URL: https://studio.flowmason.io
API Key: fm_xxxxxxxxxxxxx
```

### API Key Storage

API keys are stored securely using:
- **iOS**: Keychain Services
- **Android**: EncryptedSharedPreferences

## Push Notifications

Get notified when pipelines complete or fail.

### Enabling Notifications

1. Go to Settings
2. Toggle "Push Notifications" on
3. Allow notifications when prompted

### Notification Types

| Type | Description |
|------|-------------|
| Run Complete | Pipeline finished successfully |
| Run Failed | Pipeline failed with error |
| Run Started | Pipeline started (if subscribed) |
| Schedule Reminder | Upcoming scheduled run |

### Subscribing to Pipelines

1. Open pipeline details
2. Tap the bell icon
3. Select notification preferences

## API Integration

The mobile app uses the Studio REST API:

```typescript
// src/services/api.ts

const api = {
  // Pipeline operations
  getPipelines: () => GET('/api/v1/pipelines'),
  getPipeline: (id) => GET(`/api/v1/pipelines/${id}`),
  runPipeline: (id, inputs) => POST(`/api/v1/run`, { pipeline_id: id, inputs }),

  // Run operations
  getRuns: (filters) => GET('/api/v1/runs', filters),
  getRun: (id) => GET(`/api/v1/runs/${id}`),
  cancelRun: (id) => POST(`/api/v1/runs/${id}/cancel`),

  // Stats
  getStats: () => GET('/api/v1/stats'),

  // Health
  checkHealth: () => GET('/api/v1/health'),
};
```

## Screen Reference

### DashboardScreen

```typescript
// Main dashboard showing stats and activity
<DashboardScreen />

// Features:
// - Pipeline stats cards
// - Active runs list
// - Recent activity feed
// - Pull-to-refresh
```

### PipelinesScreen

```typescript
// Pipeline list and management
<PipelinesScreen />

// Features:
// - Searchable list
// - Filter by status
// - Tap to view details
// - Long-press for actions
```

### HistoryScreen

```typescript
// Execution history
<HistoryScreen />

// Features:
// - Date range filter
// - Status filter
// - Infinite scroll
// - Tap for details
```

### SettingsScreen

```typescript
// App configuration
<SettingsScreen />

// Features:
// - Server configuration
// - Connection test
// - Notification settings
// - Clear data option
```

## Building for Production

### iOS

```bash
# Build for iOS
eas build --platform ios --profile production

# Submit to App Store
eas submit --platform ios
```

### Android

```bash
# Build for Android
eas build --platform android --profile production

# Submit to Play Store
eas submit --platform android
```

### Configuration

Update `app.json` for your deployment:

```json
{
  "expo": {
    "name": "FlowMason",
    "slug": "flowmason-mobile",
    "version": "1.0.0",
    "ios": {
      "bundleIdentifier": "com.yourcompany.flowmason"
    },
    "android": {
      "package": "com.yourcompany.flowmason"
    }
  }
}
```

## Offline Support

The app provides limited offline functionality:
- View cached pipelines
- View cached run history
- Queue runs for when online
- Automatic sync when connected

## Security

- API keys stored in secure device storage
- HTTPS-only communication
- Session timeout after inactivity
- Biometric authentication (optional)

## Troubleshooting

### Connection Issues

1. Verify server URL is correct
2. Check API key is valid
3. Ensure server is accessible from mobile network
4. Try "Test Connection" in settings

### Notification Issues

1. Check notification permissions
2. Verify push tokens in Studio
3. Check notification settings in-app
4. Restart the app

### Data Not Updating

1. Pull down to refresh
2. Check connection status
3. Clear cache in settings
4. Log out and log back in


---

## 06-studio/multi-region.md

# Multi-Region Deployment

FlowMason Studio supports deploying pipelines across multiple geographic regions for improved reliability, latency, and compliance.

## Overview

Multi-Region Deployment provides:

- **Geographic Distribution**: Deploy to regions worldwide
- **Traffic Routing**: Smart routing based on latency, location, or rules
- **Automatic Failover**: Seamless failover when regions become unhealthy
- **Health Monitoring**: Continuous health checks across regions
- **Scaling**: Independent scaling per region
- **Metrics**: Region-specific and global metrics

## Quick Start

### List Available Regions

```http
GET /api/v1/multi-region/regions
```

**Response:**
```json
{
  "regions": [
    {
      "id": "us-east-1",
      "name": "US East (Virginia)",
      "code": "us-east-1",
      "location": "Virginia, USA",
      "status": "active",
      "supports_gpu": true,
      "max_concurrent_runs": 500,
      "available_providers": ["openai", "anthropic", "google"],
      "current_load": 0.45,
      "average_latency_ms": 25.5,
      "uptime_percentage": 99.95
    },
    {
      "id": "eu-west-1",
      "name": "Europe (Ireland)",
      "code": "eu-west-1",
      "location": "Dublin, Ireland",
      "status": "active",
      "supports_gpu": true
    }
  ],
  "total": 6
}
```

### Create a Deployment

```http
POST /api/v1/multi-region/deployments
Content-Type: application/json

{
  "pipeline_id": "my-pipeline",
  "pipeline_version": "1.0.0",
  "name": "production-deployment",
  "config": {
    "primary_region": "us-east-1",
    "replica_regions": ["eu-west-1", "ap-northeast-1"],
    "routing_strategy": "latency",
    "auto_failover_enabled": true,
    "health_check": {
      "type": "http",
      "interval_seconds": 30,
      "timeout_seconds": 10
    },
    "min_replicas_per_region": 2,
    "max_replicas_per_region": 10,
    "auto_scaling_enabled": true
  }
}
```

**Response:**
```json
{
  "id": "deploy_abc123",
  "pipeline_id": "my-pipeline",
  "pipeline_version": "1.0.0",
  "name": "production-deployment",
  "status": "active",
  "config": {...},
  "regions": [
    {
      "region_id": "us-east-1",
      "status": "active",
      "version": "1.0.0",
      "replicas": 2,
      "healthy_replicas": 2,
      "health_check_status": "healthy"
    },
    {
      "region_id": "eu-west-1",
      "status": "active",
      "replicas": 2,
      "healthy_replicas": 2
    },
    {
      "region_id": "ap-northeast-1",
      "status": "active",
      "replicas": 2,
      "healthy_replicas": 2
    }
  ]
}
```

## Regions

### Available Regions

| Region | Location | GPU | Providers |
|--------|----------|-----|-----------|
| `us-east-1` | Virginia, USA | Yes | OpenAI, Anthropic, Google |
| `us-west-2` | Oregon, USA | Yes | OpenAI, Anthropic |
| `eu-west-1` | Dublin, Ireland | Yes | OpenAI, Anthropic, Google |
| `eu-central-1` | Frankfurt, Germany | No | OpenAI, Anthropic |
| `ap-northeast-1` | Tokyo, Japan | Yes | OpenAI, Anthropic |
| `ap-southeast-1` | Singapore | No | OpenAI, Anthropic |

### Get Region Details

```http
GET /api/v1/multi-region/regions/us-east-1
```

### Get Region Endpoint

```http
GET /api/v1/multi-region/regions/us-east-1/endpoint
```

**Response:**
```json
{
  "region_id": "us-east-1",
  "api_url": "https://us-east-1.api.flowmason.io",
  "ws_url": "wss://us-east-1.api.flowmason.io/ws",
  "health_check_url": "https://us-east-1.api.flowmason.io/health"
}
```

### Find Nearest Region

```http
GET /api/v1/multi-region/regions/nearest?latitude=40.7128&longitude=-74.0060
```

## Routing Strategies

### Latency-Based (Default)

Routes requests to the region with the lowest latency.

```json
{
  "routing_strategy": "latency"
}
```

### Geolocation

Routes requests based on the user's geographic location.

```json
{
  "routing_strategy": "geolocation"
}
```

### Weighted

Distributes traffic by configured weights.

```json
{
  "routing_strategy": "weighted",
  "routing_rules": [
    {
      "id": "rule_1",
      "name": "Production weights",
      "target_regions": ["us-east-1", "eu-west-1"],
      "weights": {
        "us-east-1": 70,
        "eu-west-1": 30
      }
    }
  ]
}
```

### Failover

Uses primary region with automatic failover to replicas.

```json
{
  "routing_strategy": "failover"
}
```

### Round Robin

Equal distribution across all healthy regions.

```json
{
  "routing_strategy": "round_robin"
}
```

## Routing Rules

Custom rules for advanced routing logic:

```json
{
  "routing_rules": [
    {
      "id": "eu_users",
      "name": "Route EU users to EU region",
      "priority": 10,
      "enabled": true,
      "source_countries": ["DE", "FR", "GB", "IT", "ES"],
      "target_regions": ["eu-west-1", "eu-central-1"],
      "fallback_regions": ["us-east-1"]
    },
    {
      "id": "api_header",
      "name": "Route by API header",
      "priority": 5,
      "header_conditions": {
        "X-Preferred-Region": "asia"
      },
      "target_regions": ["ap-northeast-1", "ap-southeast-1"]
    }
  ]
}
```

### Resolve Route

```http
GET /api/v1/multi-region/deployments/{id}/route?latitude=51.5074&longitude=-0.1278&source_country=GB
```

**Response:**
```json
{
  "region_id": "eu-west-1",
  "endpoint": {
    "api_url": "https://eu-west-1.api.flowmason.io",
    "ws_url": "wss://eu-west-1.api.flowmason.io/ws"
  }
}
```

## Scaling

### Scale a Region

```http
PUT /api/v1/multi-region/deployments/{id}/regions/us-east-1/scale
Content-Type: application/json

{
  "replicas": 5
}
```

### Auto-Scaling Configuration

```json
{
  "auto_scaling_enabled": true,
  "min_replicas_per_region": 2,
  "max_replicas_per_region": 20,
  "scale_up_threshold": 0.7,
  "scale_down_threshold": 0.3
}
```

## Failover

### Automatic Failover

```json
{
  "auto_failover_enabled": true,
  "failover_threshold": 3,
  "failover_cooldown_seconds": 300
}
```

### Manual Failover

```http
POST /api/v1/multi-region/deployments/{id}/failover
Content-Type: application/json

{
  "from_region": "us-east-1",
  "to_region": "us-west-2",
  "reason": "Scheduled maintenance"
}
```

### Get Failover History

```http
GET /api/v1/multi-region/deployments/{id}/failover-events
```

**Response:**
```json
[
  {
    "id": "event_xyz",
    "from_region": "us-east-1",
    "to_region": "us-west-2",
    "reason": "Health check failures exceeded threshold",
    "triggered_at": "2024-01-15T10:30:00Z",
    "completed_at": "2024-01-15T10:30:05Z",
    "success": true,
    "affected_requests": 12
  }
]
```

## Health Checks

### Configuration

```json
{
  "health_check": {
    "type": "http",
    "interval_seconds": 30,
    "timeout_seconds": 10,
    "healthy_threshold": 2,
    "unhealthy_threshold": 3,
    "path": "/health",
    "expected_status": 200
  }
}
```

### Health Check Types

| Type | Description |
|------|-------------|
| `http` | HTTP endpoint check |
| `tcp` | TCP connection check |
| `pipeline` | Run a test pipeline |

### Run Manual Health Check

```http
POST /api/v1/multi-region/deployments/{id}/regions/us-east-1/health-check
```

## Metrics

### Global Metrics

```http
GET /api/v1/multi-region/deployments/{id}/metrics
```

**Response:**
```json
{
  "timestamp": "2024-01-15T12:00:00Z",
  "total_requests": 10000,
  "total_errors": 15,
  "global_latency_p50_ms": 85.5,
  "global_latency_p95_ms": 250.0,
  "regions": {
    "us-east-1": {
      "requests": 5000,
      "errors": 8,
      "latency_p50_ms": 50.0,
      "latency_p95_ms": 150.0,
      "cpu_usage": 0.45,
      "memory_usage": 0.55
    },
    "eu-west-1": {
      "requests": 3000,
      "errors": 5,
      "latency_p50_ms": 75.0
    }
  },
  "routing_distribution": {
    "us-east-1": 5000,
    "eu-west-1": 3000,
    "ap-northeast-1": 2000
  }
}
```

### Region Metrics

```http
GET /api/v1/multi-region/deployments/{id}/regions/us-east-1/metrics
```

## Region Management

### Add Region

```http
POST /api/v1/multi-region/deployments/{id}/regions
Content-Type: application/json

{
  "region_id": "ap-southeast-1",
  "replicas": 2,
  "weight": 10
}
```

### Remove Region

```http
DELETE /api/v1/multi-region/deployments/{id}/regions/ap-southeast-1
```

## Deployment Lifecycle

### Update Deployment

```http
PATCH /api/v1/multi-region/deployments/{id}
Content-Type: application/json

{
  "pipeline_version": "1.1.0",
  "config": {
    "routing_strategy": "weighted"
  }
}
```

### Stop Deployment

```http
POST /api/v1/multi-region/deployments/{id}/stop
```

### Delete Deployment

```http
DELETE /api/v1/multi-region/deployments/{id}
```

## Configuration Reference

```json
{
  "config": {
    "primary_region": "us-east-1",
    "replica_regions": ["eu-west-1", "ap-northeast-1"],
    "excluded_regions": [],

    "routing_strategy": "latency",
    "routing_rules": [],

    "health_check": {
      "type": "http",
      "interval_seconds": 30,
      "timeout_seconds": 10,
      "healthy_threshold": 2,
      "unhealthy_threshold": 3,
      "path": "/health",
      "expected_status": 200
    },

    "min_replicas_per_region": 1,
    "max_replicas_per_region": 10,
    "auto_scaling_enabled": true,
    "scale_up_threshold": 0.7,
    "scale_down_threshold": 0.3,

    "auto_failover_enabled": true,
    "failover_threshold": 3,
    "failover_cooldown_seconds": 300,

    "sync_state": true,
    "sync_interval_seconds": 5
  }
}
```

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/multi-region/regions` | GET | List regions |
| `/multi-region/regions/{id}` | GET | Get region |
| `/multi-region/regions/{id}/endpoint` | GET | Get endpoint |
| `/multi-region/regions/nearest` | GET | Find nearest |
| `/multi-region/deployments` | GET | List deployments |
| `/multi-region/deployments` | POST | Create deployment |
| `/multi-region/deployments/{id}` | GET | Get deployment |
| `/multi-region/deployments/{id}` | PATCH | Update deployment |
| `/multi-region/deployments/{id}/stop` | POST | Stop deployment |
| `/multi-region/deployments/{id}` | DELETE | Delete deployment |
| `/multi-region/deployments/{id}/regions` | POST | Add region |
| `/multi-region/deployments/{id}/regions/{rid}` | DELETE | Remove region |
| `/multi-region/deployments/{id}/regions/{rid}/scale` | PUT | Scale region |
| `/multi-region/deployments/{id}/failover` | POST | Trigger failover |
| `/multi-region/deployments/{id}/failover-events` | GET | Failover history |
| `/multi-region/deployments/{id}/route` | GET | Resolve route |
| `/multi-region/deployments/{id}/metrics` | GET | Global metrics |
| `/multi-region/deployments/{id}/regions/{rid}/metrics` | GET | Region metrics |
| `/multi-region/deployments/{id}/regions/{rid}/health-check` | POST | Run health check |


---

## 06-studio/natural-language-builder.md

# Natural Language Pipeline Builder

FlowMason Studio includes an AI-powered Natural Language Builder that generates complete pipelines from plain English descriptions.

## Overview

The Natural Language Builder enables:

- **Pipeline Generation**: Describe what you want, get a working pipeline
- **Intent Analysis**: Understand how your request is interpreted
- **Component Matching**: Find the right components for any task
- **Iterative Refinement**: Improve generated pipelines with feedback
- **Templates**: Start from common patterns

## Quick Start

### Generate a Pipeline

```http
POST /api/v1/nl-builder/generate
Content-Type: application/json

{
  "description": "Summarize a long article, then translate the summary to Spanish",
  "mode": "detailed"
}
```

**Response:**
```json
{
  "success": true,
  "message": "Pipeline generated successfully",
  "result": {
    "id": "gen_abc123",
    "status": "completed",
    "analysis": {
      "intent": "summarization",
      "actions": ["summarize", "translate"],
      "entities": [],
      "data_sources": ["user_input"],
      "outputs": ["text"],
      "constraints": [],
      "ambiguities": []
    },
    "suggestions": [
      {
        "component_type": "generator",
        "name": "Generator",
        "purpose": "Generate summary from input",
        "rationale": "Matches intent: summarization",
        "confidence": 0.9
      },
      {
        "component_type": "generator",
        "name": "Generator",
        "purpose": "Translate content",
        "rationale": "Required for action: translate",
        "confidence": 0.85
      }
    ],
    "pipeline": {
      "name": "Summarization Pipeline",
      "description": "Summarize a long article, then translate the summary to Spanish",
      "version": "1.0.0",
      "stages": [
        {
          "id": "generator_1",
          "name": "Generate summary from input",
          "component_type": "generator",
          "config": {
            "prompt": "Based on the following input, generate summary from input:\n\n{{input}}",
            "max_tokens": 1000,
            "temperature": 0.7
          },
          "depends_on": []
        },
        {
          "id": "generator_2",
          "name": "Translate content",
          "component_type": "generator",
          "config": {
            "prompt": "Based on the following input, translate content:\n\n{{stages.generator_1.output}}",
            "max_tokens": 1000,
            "temperature": 0.7
          },
          "depends_on": ["generator_1"]
        }
      ],
      "input_schema": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "description": "Input text to process"
          }
        },
        "required": ["text"]
      }
    }
  }
}
```

### Quick Generation

For simple pipelines, use the quick endpoint:

```http
POST /api/v1/nl-builder/quick?description=Filter%20products%20by%20price%20and%20sort%20by%20rating
```

Returns just the generated pipeline without detailed analysis.

## Generation Modes

| Mode | Description | Use Case |
|------|-------------|----------|
| `quick` | Fast generation with basic structure | Simple pipelines |
| `detailed` | Full generation with configs and analysis | Production pipelines |
| `interactive` | Step-by-step with user feedback | Complex requirements |

## Analyzing Requests

Before generating, you can analyze how your description will be interpreted:

```http
POST /api/v1/nl-builder/analyze?description=Fetch%20data%20from%20API%20and%20summarize%20it
```

**Response:**
```json
{
  "analysis": {
    "intent": "summarization",
    "entities": [],
    "actions": ["summarize", "call"],
    "data_sources": ["external_api"],
    "outputs": [],
    "constraints": [],
    "ambiguities": ["Output format not specified"]
  },
  "suggested_approach": "fetch data from external_api → perform call, summarize",
  "estimated_complexity": "moderate",
  "estimated_stages": 3
}
```

## Finding Components

Search for components that match a task:

```http
POST /api/v1/nl-builder/match-components
Content-Type: application/json

{
  "task": "filter a list of products by price",
  "limit": 3
}
```

**Response:**
```json
{
  "task": "filter a list of products by price",
  "matches": [
    {
      "component_type": "filter",
      "name": "Filter",
      "description": "Filter items based on conditions",
      "match_score": 0.4,
      "match_reason": "matches use case 'filter'"
    },
    {
      "component_type": "json_transform",
      "name": "JSON Transform",
      "description": "Transform and restructure JSON data",
      "match_score": 0.2,
      "match_reason": "contains 'data'"
    }
  ]
}
```

## Refining Pipelines

Improve a generated pipeline with feedback:

```http
POST /api/v1/nl-builder/refine
Content-Type: application/json

{
  "generation_id": "gen_abc123",
  "feedback": "Add error handling and make the output more structured as JSON"
}
```

**Response:**
```json
{
  "original_id": "gen_abc123",
  "refined_id": "gen_def456",
  "changes_made": [
    "Added stages: schema_validate_1",
    "Modified stage configurations"
  ],
  "pipeline": { ... }
}
```

## Templates

Start from predefined templates for common patterns:

### List Templates

```http
GET /api/v1/nl-builder/templates
```

**Response:**
```json
[
  {
    "id": "summarization",
    "name": "Text Summarization",
    "description": "Summarize long text into concise points",
    "category": "ai",
    "example_prompt": "Summarize this article into 3 key points",
    "stages": 1
  },
  {
    "id": "content-review",
    "name": "Content Review",
    "description": "Generate content and have it reviewed for quality",
    "category": "ai",
    "example_prompt": "Generate a product description and review it for accuracy",
    "stages": 2
  }
]
```

### Generate from Template

```http
POST /api/v1/nl-builder/from-template/content-review?customization=Focus%20on%20technical%20products
```

## Advanced Options

### Preferred/Avoided Components

Control which components are used:

```json
{
  "description": "Process and validate user data",
  "preferred_components": ["schema_validate", "json_transform"],
  "avoid_components": ["http_request"]
}
```

### Context and Examples

Provide additional context:

```json
{
  "description": "Generate a report from sales data",
  "context": {
    "available_fields": ["date", "amount", "product", "region"],
    "output_format": "markdown"
  },
  "examples": [
    {
      "input": {"sales": [{"amount": 100}]},
      "output": {"total": 100, "count": 1}
    }
  ]
}
```

## Intent Recognition

The builder recognizes these primary intents:

| Intent | Trigger Words |
|--------|---------------|
| `summarization` | summarize, summary |
| `translation` | translate, translation |
| `classification` | classify, categorize |
| `extraction` | extract, parse |
| `generation` | generate, create, write |
| `transformation` | transform, convert |
| `validation` | validate, check, verify |
| `analysis` | analyze, evaluate |

## Component Selection

Components are matched based on:

1. **Use case keywords** - Direct matches with component capabilities
2. **Description similarity** - Words found in component descriptions
3. **Name matching** - Component names in the request
4. **Action mapping** - Actions mapped to appropriate components

### Action to Component Mapping

| Action | Component |
|--------|-----------|
| filter | filter |
| transform | json_transform |
| validate | schema_validate |
| send/call | http_request |
| summarize/generate | generator |
| review/evaluate | critic |
| improve | improver |

## Python Integration

```python
from flowmason_studio.services.nl_builder_service import get_nl_builder_service
import asyncio

service = get_nl_builder_service()

async def generate():
    # Generate pipeline
    result = await service.generate_pipeline(
        description="Fetch news articles and summarize the top 5",
        mode=GenerationMode.DETAILED,
    )

    if result.pipeline:
        print(f"Generated: {result.pipeline.name}")
        for stage in result.pipeline.stages:
            print(f"  - {stage.id}: {stage.component_type}")

    # Find components
    matches = await service.find_components("filter by date", limit=3)
    for match in matches:
        print(f"{match.component_type}: {match.match_score:.2f}")

    # Analyze request
    analysis = await service.analyze_request("Process customer feedback")
    print(f"Intent: {analysis.intent}")
    print(f"Actions: {analysis.actions}")

asyncio.run(generate())
```

## Best Practices

1. **Be Specific**: Include details about inputs, outputs, and processing steps
2. **Use Action Words**: Start with verbs like "summarize", "filter", "transform"
3. **Mention Data Sources**: Specify if data comes from API, file, or user input
4. **Describe Output Format**: Mention if you need JSON, text, email, etc.
5. **Iterate with Refinement**: Use the refine endpoint to improve results

## Tips for Better Results

### Good Descriptions

- "Fetch product data from API, filter by price under $100, and generate a summary report"
- "Validate JSON input against a schema, transform to new format, and send to webhook"
- "Take a list of articles, summarize each one, then combine into a newsletter"

### Less Effective Descriptions

- "Process data" (too vague)
- "Make it work" (no specific intent)
- "Do the thing with the stuff" (unclear)

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/nl-builder/generate` | POST | Generate pipeline from description |
| `/nl-builder/quick` | POST | Quick generation (returns pipeline only) |
| `/nl-builder/generations/{id}` | GET | Get generation result |
| `/nl-builder/refine` | POST | Refine a generated pipeline |
| `/nl-builder/analyze` | POST | Analyze request without generating |
| `/nl-builder/match-components` | POST | Find matching components |
| `/nl-builder/components/search` | GET | Quick component search |
| `/nl-builder/templates` | GET | List available templates |
| `/nl-builder/from-template/{id}` | POST | Generate from template |


---

## 06-studio/oauth.md

# OAuth 2.0 Support

FlowMason Studio supports OAuth 2.0 for secure third-party application access. This enables integrations, external tools, and service-to-service authentication.

## Overview

Supported OAuth 2.0 flows:

| Flow | Use Case |
|------|----------|
| Authorization Code + PKCE | Web applications, SPAs, mobile apps |
| Client Credentials | Service-to-service, backend integrations |
| Refresh Token | Long-lived access with token rotation |

## Quick Start

### 1. Register an OAuth Client

```bash
curl -X POST http://localhost:8999/api/v1/oauth/clients \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Integration",
    "redirect_uris": ["https://myapp.com/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "scopes": ["read", "execute"]
  }'
```

Response:
```json
{
  "client_id": "oa_abc123...",
  "client_secret": "xyz789...",
  "name": "My Integration",
  "redirect_uris": ["https://myapp.com/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "scopes": ["read", "execute"],
  "is_confidential": true,
  "created_at": "2024-01-15T10:00:00Z"
}
```

**Important:** Save the `client_secret` - it's only shown once.

### 2. Get Access Token

#### Authorization Code Flow (Web Apps)

1. Redirect user to authorization endpoint:
```
GET /api/v1/oauth/authorize?
  response_type=code&
  client_id=oa_abc123&
  redirect_uri=https://myapp.com/callback&
  scope=read execute&
  state=random_state_value
```

2. User is redirected back with code:
```
https://myapp.com/callback?code=auth_code_xyz&state=random_state_value
```

3. Exchange code for tokens:
```bash
curl -X POST http://localhost:8999/api/v1/oauth/token \
  -d "grant_type=authorization_code" \
  -d "code=auth_code_xyz" \
  -d "redirect_uri=https://myapp.com/callback" \
  -d "client_id=oa_abc123" \
  -d "client_secret=xyz789"
```

#### Client Credentials Flow (Service-to-Service)

```bash
curl -X POST http://localhost:8999/api/v1/oauth/token \
  -d "grant_type=client_credentials" \
  -d "client_id=oa_abc123" \
  -d "client_secret=xyz789" \
  -d "scope=read execute"
```

### 3. Use Access Token

```bash
curl http://localhost:8999/api/v1/pipelines \
  -H "Authorization: Bearer access_token_here"
```

## Client Management

### Register Client

```bash
curl -X POST http://localhost:8999/api/v1/oauth/clients \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My App",
    "description": "Integration for pipeline automation",
    "redirect_uris": ["https://myapp.com/callback", "http://localhost:3000/callback"],
    "grant_types": ["authorization_code", "refresh_token", "client_credentials"],
    "scopes": ["read", "write", "execute"],
    "is_confidential": true
  }'
```

### List Clients

```bash
curl http://localhost:8999/api/v1/oauth/clients?org_id=org_default
```

### Get Client Details

```bash
curl http://localhost:8999/api/v1/oauth/clients/{client_id}
```

### Delete Client

```bash
curl -X DELETE http://localhost:8999/api/v1/oauth/clients/{client_id}
```

This also revokes all tokens issued to the client.

### Regenerate Client Secret

```bash
curl -X POST http://localhost:8999/api/v1/oauth/clients/{client_id}/regenerate-secret
```

The old secret is immediately invalidated.

## Authorization Code Flow

### With PKCE (Recommended)

PKCE (Proof Key for Code Exchange) is recommended for all clients, especially public clients (SPAs, mobile apps).

1. Generate code verifier and challenge:
```javascript
// Generate random verifier (43-128 characters)
const verifier = generateRandomString(64);

// Create S256 challenge
const challenge = base64url(sha256(verifier));
```

2. Include in authorization request:
```
GET /api/v1/oauth/authorize?
  response_type=code&
  client_id=oa_abc123&
  redirect_uri=https://myapp.com/callback&
  scope=read execute&
  state=random_state&
  code_challenge=challenge_here&
  code_challenge_method=S256
```

3. Include verifier in token exchange:
```bash
curl -X POST http://localhost:8999/api/v1/oauth/token \
  -d "grant_type=authorization_code" \
  -d "code=auth_code_xyz" \
  -d "redirect_uri=https://myapp.com/callback" \
  -d "client_id=oa_abc123" \
  -d "code_verifier=verifier_here"
```

### Without PKCE (Confidential Clients Only)

```bash
curl -X POST http://localhost:8999/api/v1/oauth/token \
  -d "grant_type=authorization_code" \
  -d "code=auth_code_xyz" \
  -d "redirect_uri=https://myapp.com/callback" \
  -d "client_id=oa_abc123" \
  -d "client_secret=xyz789"
```

## Token Refresh

Access tokens expire after 1 hour. Use refresh tokens to get new access tokens:

```bash
curl -X POST http://localhost:8999/api/v1/oauth/token \
  -d "grant_type=refresh_token" \
  -d "refresh_token=rtok_xyz" \
  -d "client_id=oa_abc123" \
  -d "client_secret=xyz789"
```

Response includes a new refresh token (rotation):
```json
{
  "access_token": "new_access_token",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "new_refresh_token",
  "scope": "read execute"
}
```

**Important:** Use the new refresh token for subsequent refreshes.

## Token Introspection

Validate a token (RFC 7662):

```bash
curl -X POST http://localhost:8999/api/v1/oauth/introspect \
  -d "token=access_token_here"
```

Response:
```json
{
  "active": true,
  "token_type": "Bearer",
  "scope": "read execute",
  "client_id": "oa_abc123",
  "sub": "user_xyz",
  "exp": 1705320000,
  "iat": 1705316400
}
```

Inactive/expired tokens return:
```json
{
  "active": false
}
```

## Token Revocation

Revoke a token (RFC 7009):

```bash
curl -X POST http://localhost:8999/api/v1/oauth/revoke \
  -d "token=access_token_here"
```

Always returns success (per RFC 7009).

## Scopes

| Scope | Description |
|-------|-------------|
| `read` | Read access to pipelines, components |
| `write` | Create and edit pipelines |
| `execute` | Run pipeline executions |
| `admin` | Administrative operations |
| `openid` | OpenID Connect (user identity) |
| `profile` | User profile information |
| `email` | User email address |

Request scopes in the authorization request:
```
scope=read execute write
```

## Client Types

### Confidential Clients

Server-side applications that can securely store secrets.

```json
{
  "name": "Backend Service",
  "is_confidential": true,
  "grant_types": ["client_credentials", "authorization_code", "refresh_token"]
}
```

### Public Clients

Browser apps (SPAs) and mobile apps that cannot securely store secrets.

```json
{
  "name": "Mobile App",
  "is_confidential": false,
  "grant_types": ["authorization_code", "refresh_token"]
}
```

**Note:** Public clients MUST use PKCE and cannot use client_credentials flow.

## Server Metadata

Discover server configuration (RFC 8414):

```bash
curl http://localhost:8999/api/v1/oauth/.well-known/oauth-authorization-server
```

Response:
```json
{
  "issuer": "http://localhost:8999",
  "authorization_endpoint": "http://localhost:8999/api/v1/oauth/authorize",
  "token_endpoint": "http://localhost:8999/api/v1/oauth/token",
  "introspection_endpoint": "http://localhost:8999/api/v1/oauth/introspect",
  "revocation_endpoint": "http://localhost:8999/api/v1/oauth/revoke",
  "registration_endpoint": "http://localhost:8999/api/v1/oauth/clients",
  "scopes_supported": ["read", "write", "execute", "admin", "openid", "profile", "email"],
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "client_credentials", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
  "code_challenge_methods_supported": ["plain", "S256"]
}
```

## Security Best Practices

1. **Always use HTTPS** in production
2. **Use PKCE** for all authorization code flows
3. **Validate redirect URIs** - register exact URIs
4. **Store secrets securely** - never in client-side code
5. **Use short-lived access tokens** (1 hour default)
6. **Rotate refresh tokens** - old tokens are invalidated
7. **Validate state parameter** to prevent CSRF
8. **Request minimal scopes** needed for your use case

## Example: Node.js Integration

```javascript
const axios = require('axios');

class FlowMasonOAuth {
  constructor(clientId, clientSecret, baseUrl = 'http://localhost:8999') {
    this.clientId = clientId;
    this.clientSecret = clientSecret;
    this.baseUrl = baseUrl;
  }

  // Client credentials flow
  async getServiceToken(scopes = ['read', 'execute']) {
    const response = await axios.post(
      `${this.baseUrl}/api/v1/oauth/token`,
      new URLSearchParams({
        grant_type: 'client_credentials',
        client_id: this.clientId,
        client_secret: this.clientSecret,
        scope: scopes.join(' '),
      })
    );
    return response.data;
  }

  // Refresh token
  async refreshToken(refreshToken) {
    const response = await axios.post(
      `${this.baseUrl}/api/v1/oauth/token`,
      new URLSearchParams({
        grant_type: 'refresh_token',
        refresh_token: refreshToken,
        client_id: this.clientId,
        client_secret: this.clientSecret,
      })
    );
    return response.data;
  }
}

// Usage
const oauth = new FlowMasonOAuth('oa_abc123', 'secret_xyz');
const tokens = await oauth.getServiceToken();
console.log('Access token:', tokens.access_token);
```

## Example: Python Integration

```python
import httpx

class FlowMasonOAuth:
    def __init__(self, client_id: str, client_secret: str, base_url: str = "http://localhost:8999"):
        self.client_id = client_id
        self.client_secret = client_secret
        self.base_url = base_url

    async def get_service_token(self, scopes: list[str] = None) -> dict:
        """Get token via client credentials flow."""
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.base_url}/api/v1/oauth/token",
                data={
                    "grant_type": "client_credentials",
                    "client_id": self.client_id,
                    "client_secret": self.client_secret,
                    "scope": " ".join(scopes or ["read", "execute"]),
                }
            )
            response.raise_for_status()
            return response.json()

    async def refresh_token(self, refresh_token: str) -> dict:
        """Refresh access token."""
        async with httpx.AsyncClient() as client:
            response = await client.post(
                f"{self.base_url}/api/v1/oauth/token",
                data={
                    "grant_type": "refresh_token",
                    "refresh_token": refresh_token,
                    "client_id": self.client_id,
                    "client_secret": self.client_secret,
                }
            )
            response.raise_for_status()
            return response.json()

# Usage
import asyncio

async def main():
    oauth = FlowMasonOAuth("oa_abc123", "secret_xyz")
    tokens = await oauth.get_service_token()
    print(f"Access token: {tokens['access_token']}")

asyncio.run(main())
```

## Token Lifetimes

| Token Type | Default Lifetime |
|------------|------------------|
| Authorization Code | 10 minutes |
| Access Token | 1 hour |
| Refresh Token | 30 days |

## Error Responses

OAuth errors follow RFC 6749:

```json
{
  "error": "invalid_grant",
  "error_description": "Invalid or expired code"
}
```

Common errors:

| Error | Description |
|-------|-------------|
| `invalid_request` | Missing required parameter |
| `invalid_client` | Client authentication failed |
| `invalid_grant` | Invalid code or refresh token |
| `unauthorized_client` | Client not authorized for grant type |
| `unsupported_grant_type` | Grant type not supported |
| `invalid_scope` | Requested scope not allowed |


---

## 06-studio/prompt-ab-testing.md

# Prompt A/B Testing

FlowMason supports A/B testing for prompts, allowing you to compare different prompt variants and determine which performs better using statistical analysis.

## Overview

Prompt A/B testing enables:
- **Variant Comparison**: Test multiple prompt versions side-by-side
- **Traffic Allocation**: Control what percentage of requests use each variant
- **Metric Collection**: Track latency, ratings, custom metrics
- **Statistical Analysis**: Determine winners with confidence levels
- **Sticky Assignment**: Users consistently see the same variant

## Creating an Experiment

### Basic Experiment

```http
POST /api/v1/experiments
Content-Type: application/json

{
  "name": "Summarization Prompt Test",
  "description": "Testing concise vs detailed summaries",
  "variants": [
    {
      "name": "Control",
      "is_control": true,
      "content": "Summarize the following text:\n\n{{text}}",
      "weight": 1.0
    },
    {
      "name": "Concise",
      "content": "Summarize the following text in 2-3 sentences:\n\n{{text}}",
      "weight": 1.0
    },
    {
      "name": "Detailed",
      "content": "Provide a detailed summary with key points:\n\n{{text}}",
      "weight": 1.0
    }
  ],
  "metrics": [
    {
      "name": "rating",
      "type": "rating",
      "description": "User satisfaction (1-5)",
      "higher_is_better": true
    },
    {
      "name": "latency",
      "type": "latency",
      "description": "Response time in ms",
      "higher_is_better": false
    }
  ],
  "primary_metric": "rating",
  "min_samples_per_variant": 100
}
```

### Using Existing Prompts

```json
{
  "name": "Template Comparison",
  "variants": [
    {
      "name": "Current Template",
      "is_control": true,
      "prompt_id": "prompt_abc123"
    },
    {
      "name": "New Template",
      "prompt_id": "prompt_xyz789"
    }
  ]
}
```

### Targeting Specific Pipelines

```json
{
  "name": "Pipeline-Specific Test",
  "pipeline_ids": ["pipe_abc123", "pipe_def456"],
  "stage_ids": ["stage_summarize"],
  "user_percentage": 50.0,
  "variants": [...]
}
```

## Experiment Lifecycle

### 1. Create (Draft)
```http
POST /api/v1/experiments
```

### 2. Start (Running)
```http
POST /api/v1/experiments/{id}/start
```

### 3. Collect Data
Variant selection and metric recording happen automatically during pipeline execution.

### 4. Pause (Optional)
```http
POST /api/v1/experiments/{id}/pause
```

### 5. Complete
```http
POST /api/v1/experiments/{id}/complete
```

## Variant Selection

### Automatic Selection

```http
POST /api/v1/experiments/{experiment_id}/select
Content-Type: application/json

{
  "user_id": "user_123",
  "pipeline_id": "pipe_abc",
  "stage_id": "summarize"
}
```

**Response:**
```json
{
  "experiment_id": "exp_abc123",
  "variant_id": "var_001",
  "variant_name": "Concise",
  "prompt_content": "Summarize the following text in 2-3 sentences:\n\n{{text}}",
  "system_prompt": null,
  "model": "claude-3-5-sonnet-latest",
  "temperature": 0.7,
  "max_tokens": 500,
  "is_control": false
}
```

### Sticky Assignment

Users are consistently assigned to the same variant using a hash of their user ID and experiment ID. This ensures:
- Consistent experience for each user
- No variant switching mid-session
- Reliable A/B comparison

## Recording Metrics

### Single Metric

```http
POST /api/v1/experiments/{experiment_id}/metrics
Content-Type: application/json

{
  "variant_id": "var_001",
  "metric_name": "rating",
  "value": 4.5,
  "user_id": "user_123",
  "run_id": "run_abc"
}
```

### Batch Metrics

```http
POST /api/v1/experiments/{experiment_id}/metrics/batch
Content-Type: application/json

{
  "variant_id": "var_001",
  "metrics": {
    "rating": 4.5,
    "latency": 1250,
    "tokens": 350
  },
  "user_id": "user_123",
  "run_id": "run_abc"
}
```

## Getting Results

```http
GET /api/v1/experiments/{experiment_id}/results
```

**Response:**
```json
{
  "experiment_id": "exp_abc123",
  "experiment_name": "Summarization Prompt Test",
  "status": "running",
  "primary_metric": "rating",
  "variant_stats": [
    {
      "variant_id": "var_001",
      "variant_name": "Control",
      "is_control": true,
      "impressions": 1250,
      "samples": 1180,
      "metrics": {
        "rating": {
          "mean": 3.8,
          "std": 0.9,
          "min": 1.0,
          "max": 5.0,
          "p50": 4.0,
          "p95": 5.0
        }
      }
    },
    {
      "variant_id": "var_002",
      "variant_name": "Concise",
      "is_control": false,
      "impressions": 1245,
      "samples": 1175,
      "metrics": {
        "rating": {
          "mean": 4.2,
          "std": 0.7,
          "min": 2.0,
          "max": 5.0,
          "p50": 4.0,
          "p95": 5.0
        }
      },
      "lift_vs_control": 10.5,
      "p_value": 0.01,
      "is_significant": true
    }
  ],
  "has_winner": true,
  "winner_variant_id": "var_002",
  "winner_variant_name": "Concise",
  "confidence_level": 0.99,
  "recommendation": "'Concise' outperforms control by 10.5% on rating. Confidence: 99.0%",
  "total_samples": 2355,
  "duration_hours": 72.5
}
```

## Metric Types

| Type | Description | Example Values |
|------|-------------|----------------|
| `latency` | Response time in ms | 250, 1500, 3000 |
| `tokens` | Token count | 100, 500, 2000 |
| `rating` | User rating (1-5) | 1, 3, 4.5, 5 |
| `thumbs` | Binary feedback | 0, 1 |
| `completion` | Task completion rate | 0.0 - 1.0 |
| `custom` | Any numeric value | Any float |

## Statistical Analysis

### Confidence Levels

Results show statistical significance using Welch's t-test:

| p-value | Significance | Confidence |
|---------|-------------|------------|
| < 0.01 | Very significant | > 99% |
| < 0.05 | Significant | > 95% |
| < 0.10 | Marginally significant | > 90% |
| >= 0.10 | Not significant | < 90% |

### Minimum Sample Size

Set `min_samples_per_variant` to ensure statistical validity:
- Small effects: 1000+ samples per variant
- Medium effects: 500+ samples
- Large effects: 100+ samples

## Python Integration

### Selecting Variants

```python
from flowmason_studio.services.experiment_storage import get_experiment_storage

storage = get_experiment_storage()

# Select variant for user
result = storage.select_variant(
    experiment_id="exp_abc123",
    user_id="user_456",
    pipeline_id="pipe_summarize",
)

if result:
    experiment, variant = result
    # Use variant.content for prompt
    print(f"Using variant: {variant.name}")
```

### Recording Metrics

```python
# Record single metric
storage.record_metric(
    experiment_id="exp_abc123",
    variant_id="var_001",
    metric_name="rating",
    value=4.5,
    user_id="user_456",
)

# Record multiple metrics
storage.record_metrics(
    experiment_id="exp_abc123",
    variant_id="var_001",
    metrics={
        "rating": 4.5,
        "latency": 1250,
        "tokens": 350,
    },
    user_id="user_456",
)
```

### Getting Results

```python
results = storage.get_results("exp_abc123")

if results.has_winner:
    print(f"Winner: {results.winner_variant_name}")
    print(f"Confidence: {results.confidence_level * 100:.1f}%")
    print(f"Recommendation: {results.recommendation}")
```

## Best Practices

1. **Start with a Control**: Always include your current prompt as the control variant
2. **Equal Weights Initially**: Start with equal traffic allocation
3. **Sufficient Sample Size**: Wait for minimum samples before drawing conclusions
4. **Single Variable Testing**: Change one thing at a time between variants
5. **Monitor Early**: Check for obvious issues in the first few hours
6. **Document Variants**: Use clear names and descriptions

## Traffic Allocation

### Equal Split
```json
{
  "variants": [
    {"name": "Control", "weight": 1.0},
    {"name": "Variant A", "weight": 1.0},
    {"name": "Variant B", "weight": 1.0}
  ]
}
```

### Weighted Split (80/20)
```json
{
  "variants": [
    {"name": "Control", "weight": 4.0},
    {"name": "Risky Variant", "weight": 1.0}
  ]
}
```

### Partial Rollout
```json
{
  "user_percentage": 10.0,
  "variants": [...]
}
```
Only 10% of users participate in the experiment.

## API Reference

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/experiments` | GET | List experiments |
| `/experiments` | POST | Create experiment |
| `/experiments/{id}` | GET | Get experiment |
| `/experiments/{id}` | PUT | Update experiment |
| `/experiments/{id}` | DELETE | Delete experiment |
| `/experiments/{id}/start` | POST | Start experiment |
| `/experiments/{id}/pause` | POST | Pause experiment |
| `/experiments/{id}/resume` | POST | Resume experiment |
| `/experiments/{id}/complete` | POST | Complete experiment |
| `/experiments/{id}/select` | POST | Select variant |
| `/experiments/{id}/metrics` | POST | Record metric |
| `/experiments/{id}/metrics/batch` | POST | Record multiple metrics |
| `/experiments/{id}/results` | GET | Get results |
| `/experiments/{id}/declare-winner` | POST | Manually declare winner |
| `/experiments/running` | GET | List running experiments |
| `/experiments/stats` | GET | Get statistics |


---

## 06-studio/prompt-library.md

# Prompt Library

FlowMason Studio includes a prompt library for managing reusable prompt templates that can be shared across stages and pipelines.

## Overview

The prompt library allows you to:
- Create and manage reusable prompt templates
- Use variables for dynamic content
- Share prompts across your organization
- Track usage and versioning
- Set recommended model parameters

## Creating Prompts

### Basic Template

```bash
curl -X POST http://localhost:8999/api/v1/prompts \
  -H "Content-Type: application/json" \
  -d '{
    "name": "summarizer",
    "content": "Summarize the following {{content_type}} in {{language}}:\n\n{{content}}",
    "description": "Summarize any content type",
    "category": "summarization",
    "tags": ["summary", "content"],
    "default_values": {
      "language": "English",
      "content_type": "text"
    }
  }'
```

### With System Prompt

```bash
curl -X POST http://localhost:8999/api/v1/prompts \
  -H "Content-Type: application/json" \
  -d '{
    "name": "code-reviewer",
    "system_prompt": "You are an expert code reviewer with deep knowledge of {{language}} best practices.",
    "content": "Review the following code for bugs, security issues, and improvements:\n\n```{{language}}\n{{code}}\n```",
    "category": "code-review",
    "recommended_model": "claude-3-5-sonnet-latest",
    "temperature": 0.3
  }'
```

## Variable Syntax

Use `{{variable_name}}` for dynamic content:

```
Extract {{entity_type}} entities from the following text:

{{input_text}}

Return the results as {{output_format}}.
```

Variables are automatically detected and listed in the `variables` field.

## Rendering Prompts

Substitute variables to get the final prompt:

```bash
curl -X POST http://localhost:8999/api/v1/prompts/{prompt_id}/render \
  -H "Content-Type: application/json" \
  -d '{
    "variables": {
      "content_type": "article",
      "language": "French",
      "content": "The quick brown fox..."
    }
  }'
```

Response:
```json
{
  "content": "Summarize the following article in French:\n\nThe quick brown fox...",
  "system_prompt": null
}
```

## Using in Pipelines

Reference prompts in your pipeline stages:

```json
{
  "id": "summarize",
  "component_type": "generator",
  "config": {
    "prompt_template_id": "prompt-abc123",
    "variables": {
      "content": "{{stages.fetch-data.output.text}}",
      "language": "Spanish"
    }
  }
}
```

Or by name:
```json
{
  "config": {
    "prompt_template_name": "summarizer",
    "variables": { ... }
  }
}
```

## Listing Prompts

### All Prompts

```bash
curl http://localhost:8999/api/v1/prompts
```

### By Category

```bash
curl "http://localhost:8999/api/v1/prompts?category=summarization"
```

### Search

```bash
curl "http://localhost:8999/api/v1/prompts?search=code"
```

### List Categories

```bash
curl http://localhost:8999/api/v1/prompts/categories
```

## Getting Prompts

### By ID

```bash
curl http://localhost:8999/api/v1/prompts/{prompt_id}
```

### By Name

```bash
curl http://localhost:8999/api/v1/prompts/by-name/summarizer
```

## Updating Prompts

```bash
curl -X PATCH http://localhost:8999/api/v1/prompts/{prompt_id} \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Updated prompt content with {{new_variable}}",
    "temperature": 0.7
  }'
```

Updates automatically increment the version number.

## Duplicating Prompts

Copy a prompt (including public prompts from other orgs):

```bash
curl -X POST "http://localhost:8999/api/v1/prompts/{prompt_id}/duplicate?name=my-copy"
```

## Deleting Prompts

```bash
curl -X DELETE http://localhost:8999/api/v1/prompts/{prompt_id}
```

## Prompt Fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | string | Unique identifier |
| `name` | string | Template name |
| `content` | string | Prompt text with `{{variables}}` |
| `system_prompt` | string | Optional system prompt |
| `description` | string | Human-readable description |
| `category` | string | Category for organization |
| `tags` | array | Tags for filtering |
| `variables` | array | Auto-extracted variable names |
| `default_values` | object | Default variable values |
| `recommended_model` | string | Suggested model ID |
| `temperature` | number | Suggested temperature (0-2) |
| `max_tokens` | number | Suggested max tokens |
| `version` | string | Semantic version |
| `usage_count` | number | Times rendered |
| `is_public` | boolean | Visible to all organizations |
| `is_featured` | boolean | Featured in gallery |

## Categories

Common prompt categories:
- `extraction` - Extract structured data
- `generation` - Generate content
- `summarization` - Summarize content
- `translation` - Translate text
- `analysis` - Analyze data/text
- `code-review` - Review code
- `code-generation` - Generate code
- `classification` - Classify content
- `qa` - Question answering
- `chat` - Conversational prompts

## Sharing Prompts

### Public Prompts

Make a prompt available to all organizations:

```bash
curl -X PATCH http://localhost:8999/api/v1/prompts/{prompt_id} \
  -H "Content-Type: application/json" \
  -d '{"is_public": true}'
```

Public prompts:
- Are visible to all organizations
- Can be duplicated by anyone
- Cannot be modified by other organizations

### Private Prompts

By default, prompts are private to your organization.

## Best Practices

1. **Use descriptive names**: `extract-customer-info` > `prompt1`
2. **Document variables**: Include examples in the description
3. **Set sensible defaults**: Provide default_values where possible
4. **Choose appropriate categories**: Makes browsing easier
5. **Include model recommendations**: Help users get best results
6. **Version your changes**: The system auto-versions on update

## Example Prompts

### Entity Extraction

```json
{
  "name": "extract-entities",
  "content": "Extract all {{entity_types}} from the following text. Return as JSON array.\n\nText: {{text}}\n\nEntities:",
  "category": "extraction",
  "default_values": {
    "entity_types": "person names, organizations, and locations"
  },
  "recommended_model": "claude-3-5-sonnet-latest",
  "temperature": 0
}
```

### Code Explanation

```json
{
  "name": "explain-code",
  "system_prompt": "You are a patient teacher who explains code clearly.",
  "content": "Explain what this {{language}} code does, step by step:\n\n```{{language}}\n{{code}}\n```",
  "category": "code-review",
  "default_values": {
    "language": "Python"
  }
}
```

### Translation

```json
{
  "name": "translator",
  "content": "Translate the following text from {{source_language}} to {{target_language}}. Preserve formatting.\n\nText: {{text}}\n\nTranslation:",
  "category": "translation",
  "default_values": {
    "source_language": "English"
  }
}
```

## Database Storage

Prompts are stored in the `prompt_templates` table with support for both SQLite (development) and PostgreSQL (production). Variables are automatically extracted and stored for quick reference.


---

## 06-studio/scheduling.md

# Pipeline Scheduling

FlowMason Studio includes a built-in scheduler for running pipelines automatically based on cron expressions.

## Overview

The scheduler allows you to:
- Schedule pipelines to run at specific times
- Use cron expressions for flexible scheduling
- Pass inputs to scheduled runs
- Track run history and status
- Manually trigger scheduled runs

## Creating a Schedule

### Via API

```bash
curl -X POST http://localhost:8999/api/v1/schedules \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily Report",
    "pipeline_id": "abc123",
    "pipeline_name": "generate-report",
    "cron_expression": "0 9 * * *",
    "timezone": "America/New_York",
    "inputs": {
      "format": "pdf",
      "recipients": ["team@example.com"]
    },
    "description": "Generate daily report at 9am ET"
  }'
```

### Schedule Fields

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Display name for the schedule |
| `pipeline_id` | string | Yes | ID of the pipeline to run |
| `pipeline_name` | string | Yes | Pipeline name for display |
| `cron_expression` | string | Yes | Cron schedule expression |
| `timezone` | string | No | Timezone (default: "UTC") |
| `inputs` | object | No | Inputs to pass to the pipeline |
| `description` | string | No | Schedule description |
| `enabled` | boolean | No | Whether schedule is active (default: true) |

## Cron Expressions

Cron expressions follow the standard 5-field format:

```
┌───────────── minute (0-59)
│ ┌───────────── hour (0-23)
│ │ ┌───────────── day of month (1-31)
│ │ │ ┌───────────── month (1-12)
│ │ │ │ ┌───────────── day of week (0-6, Sun=0)
│ │ │ │ │
* * * * *
```

### Common Examples

| Expression | Description |
|------------|-------------|
| `0 9 * * *` | Daily at 9:00 AM |
| `0 9 * * 1-5` | Weekdays at 9:00 AM |
| `*/15 * * * *` | Every 15 minutes |
| `0 */2 * * *` | Every 2 hours |
| `0 0 * * 0` | Weekly on Sunday at midnight |
| `0 0 1 * *` | Monthly on the 1st at midnight |
| `0 6,12,18 * * *` | At 6am, 12pm, and 6pm daily |
| `30 4 1,15 * *` | At 4:30 AM on the 1st and 15th |

### Validate Expression

Check if a cron expression is valid and see upcoming run times:

```bash
curl "http://localhost:8999/api/v1/schedules/cron/validate?expression=0%209%20*%20*%20*&timezone=America/New_York"
```

Response:
```json
{
  "valid": true,
  "expression": "0 9 * * *",
  "timezone": "America/New_York",
  "next_runs": [
    "2024-01-15T09:00:00-05:00",
    "2024-01-16T09:00:00-05:00",
    "2024-01-17T09:00:00-05:00",
    "2024-01-18T09:00:00-05:00",
    "2024-01-19T09:00:00-05:00"
  ]
}
```

## Managing Schedules

### List Schedules

```bash
# List all schedules
curl http://localhost:8999/api/v1/schedules

# Filter by pipeline
curl "http://localhost:8999/api/v1/schedules?pipeline_id=abc123"

# Only enabled schedules
curl "http://localhost:8999/api/v1/schedules?enabled_only=true"
```

### Get Schedule

```bash
curl http://localhost:8999/api/v1/schedules/{schedule_id}
```

### Update Schedule

```bash
curl -X PATCH http://localhost:8999/api/v1/schedules/{schedule_id} \
  -H "Content-Type: application/json" \
  -d '{
    "cron_expression": "0 10 * * *",
    "inputs": {"format": "csv"}
  }'
```

### Enable/Disable Schedule

```bash
# Disable
curl -X POST http://localhost:8999/api/v1/schedules/{schedule_id}/disable

# Enable
curl -X POST http://localhost:8999/api/v1/schedules/{schedule_id}/enable
```

### Delete Schedule

```bash
curl -X DELETE http://localhost:8999/api/v1/schedules/{schedule_id}
```

## Manual Triggers

Run a scheduled pipeline immediately:

```bash
curl -X POST http://localhost:8999/api/v1/schedules/{schedule_id}/trigger
```

Response:
```json
{
  "run_id": "run-xyz789",
  "schedule_id": "sched-abc123",
  "message": "Pipeline execution started"
}
```

This doesn't affect the next scheduled run time.

## Run History

View execution history for a schedule:

```bash
curl http://localhost:8999/api/v1/schedules/{schedule_id}/history
```

Response:
```json
[
  {
    "id": "record-1",
    "schedule_id": "sched-abc123",
    "run_id": "run-xyz789",
    "scheduled_at": "2024-01-15T09:00:00Z",
    "started_at": "2024-01-15T09:00:02Z",
    "status": "completed",
    "error_message": null
  },
  {
    "id": "record-2",
    "schedule_id": "sched-abc123",
    "run_id": "run-xyz456",
    "scheduled_at": "2024-01-14T09:00:00Z",
    "started_at": "2024-01-14T09:00:01Z",
    "status": "failed",
    "error_message": "Connection timeout"
  }
]
```

## Schedule Response

Full schedule response includes:

```json
{
  "id": "sched-abc123",
  "name": "Daily Report",
  "pipeline_id": "abc123",
  "pipeline_name": "generate-report",
  "org_id": "default",
  "cron_expression": "0 9 * * *",
  "inputs": {"format": "pdf"},
  "enabled": true,
  "timezone": "America/New_York",
  "description": "Generate daily report at 9am ET",
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-10T12:00:00Z",
  "next_run_at": "2024-01-16T09:00:00-05:00",
  "last_run_at": "2024-01-15T09:00:02Z",
  "last_run_id": "run-xyz789",
  "last_run_status": "completed",
  "run_count": 15,
  "failure_count": 1
}
```

## Configuration

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `FLOWMASON_SCHEDULER_ENABLED` | `true` | Enable/disable the scheduler |
| `FLOWMASON_SCHEDULER_POLL_INTERVAL` | `60` | Seconds between schedule checks |
| `FLOWMASON_SCHEDULER_MAX_CONCURRENT` | `5` | Max concurrent scheduled runs |

### Disable Scheduler

To disable the scheduler (useful for worker nodes in a cluster):

```bash
FLOWMASON_SCHEDULER_ENABLED=false fm studio
```

## Timezones

Schedules support IANA timezone names:

```json
{
  "timezone": "America/New_York"
}
```

Common timezones:
- `UTC` - Coordinated Universal Time
- `America/New_York` - Eastern Time
- `America/Chicago` - Central Time
- `America/Denver` - Mountain Time
- `America/Los_Angeles` - Pacific Time
- `Europe/London` - British Time
- `Europe/Paris` - Central European Time
- `Asia/Tokyo` - Japan Standard Time
- `Australia/Sydney` - Australian Eastern Time

## Best Practices

1. **Use descriptive names**: Make it clear what the schedule does
2. **Set appropriate timezones**: Use the timezone where the schedule makes sense
3. **Monitor failures**: Check `failure_count` and review run history
4. **Test with manual triggers**: Verify pipeline works before scheduling
5. **Stagger schedules**: Avoid scheduling many pipelines at the same time
6. **Use specific times**: Prefer `0 9 * * *` over `* 9 * * *`

## Dependencies

The scheduler requires the `croniter` package:

```bash
pip install croniter
# or
pip install flowmason[scheduling]
```

## Database Storage

Schedules are stored in SQLite (development) or PostgreSQL (production):

- `schedules` table: Schedule configurations
- `schedule_runs` table: Run history

The scheduler uses the same database as other Studio services.


---

## 06-studio/system-diagnostics.md

# System Diagnostics API

FlowMason Studio provides a system diagnostics API for health monitoring, troubleshooting, and admin operations.

## Overview

The system API provides:
- Detailed health checks for all components
- System and platform information
- Database status and statistics
- LLM provider connectivity status
- Resource usage metrics
- Recent log access

## Health Check

Get detailed health status:

```bash
curl http://localhost:8999/api/v1/system/health
```

Response:
```json
{
  "status": "healthy",
  "version": "1.0.0",
  "uptime_seconds": 3600.5,
  "components": [
    {
      "name": "database",
      "status": "healthy",
      "message": "25 pipelines",
      "latency_ms": 2.5
    },
    {
      "name": "registry",
      "status": "healthy",
      "message": "15 components"
    },
    {
      "name": "providers",
      "status": "healthy",
      "message": "2 providers configured"
    }
  ],
  "timestamp": "2024-01-15T10:30:00Z"
}
```

### Health Statuses

| Status | Description |
|--------|-------------|
| `healthy` | All components functioning normally |
| `degraded` | Some components have issues but system is operational |
| `unhealthy` | Critical components are failing |

## System Information

Get platform and environment details:

```bash
curl http://localhost:8999/api/v1/system/info
```

Response:
```json
{
  "version": "1.0.0",
  "python_version": "3.11.4",
  "platform": "Darwin",
  "platform_version": "23.0.0",
  "hostname": "macbook-pro",
  "working_directory": "/Users/dev/flowmason-project",
  "environment": "development"
}
```

### Environments

| Environment | Description |
|-------------|-------------|
| `development` | Local development (default) |
| `staging` | Staging/test environment |
| `production` | Production deployment |

Set via `FLOWMASON_ENV` environment variable.

## Database Status

Get database status and statistics:

```bash
curl http://localhost:8999/api/v1/system/database
```

Response:
```json
{
  "type": "sqlite",
  "connected": true,
  "pipeline_count": 25,
  "run_count": 150,
  "size_bytes": 1048576
}
```

## Provider Status

Get LLM provider configuration status:

```bash
curl http://localhost:8999/api/v1/system/providers
```

Response:
```json
[
  {
    "name": "anthropic",
    "configured": true,
    "available": true,
    "default": true
  },
  {
    "name": "openai",
    "configured": true,
    "available": true,
    "default": false
  },
  {
    "name": "google",
    "configured": false,
    "available": false,
    "default": false
  }
]
```

## Resource Usage

Get memory and CPU usage (requires `psutil`):

```bash
curl http://localhost:8999/api/v1/system/resources
```

Response:
```json
{
  "memory_mb": 256.5,
  "cpu_percent": 5.2,
  "disk_usage_percent": 45.0,
  "open_file_count": 12
}
```

Note: Metrics may be empty if `psutil` is not installed.

## Complete Diagnostics

Get a complete diagnostics report:

```bash
curl http://localhost:8999/api/v1/system/diagnostics
```

Response:
```json
{
  "health": { ... },
  "system": { ... },
  "database": { ... },
  "providers": [ ... ],
  "resources": { ... },
  "registry": {
    "total_components": 15,
    "categories": {
      "core": 5,
      "control_flow": 3,
      "ai": 4,
      "http": 1,
      "utility": 2
    }
  }
}
```

## Configuration

Get non-sensitive configuration:

```bash
curl http://localhost:8999/api/v1/system/config
```

Response:
```json
{
  "environment": "development",
  "default_provider": "anthropic",
  "scheduler_enabled": true,
  "debug_mode": false,
  "cors_origins": "*",
  "log_level": "INFO"
}
```

## Recent Logs

Get recent log entries:

```bash
curl "http://localhost:8999/api/v1/system/logs/recent?limit=50"
```

Filter by level:
```bash
curl "http://localhost:8999/api/v1/system/logs/recent?limit=50&level=ERROR"
```

Response:
```json
{
  "count": 50,
  "logs": [
    {
      "timestamp": "2024-01-15T10:30:00Z",
      "level": "INFO",
      "category": "execution",
      "message": "Pipeline run_abc123 completed"
    }
  ]
}
```

## Garbage Collection

Trigger Python garbage collection:

```bash
curl -X POST http://localhost:8999/api/v1/system/gc
```

Response:
```json
{
  "message": "Garbage collection completed",
  "objects_collected": 1500,
  "generation_counts_before": [100, 50, 25],
  "generation_counts_after": [10, 5, 2]
}
```

## Use Cases

### Health Monitoring

```python
import httpx

async def check_health():
    response = await httpx.get("http://localhost:8999/api/v1/system/health")
    data = response.json()

    if data["status"] != "healthy":
        print(f"System is {data['status']}")
        for component in data["components"]:
            if component["status"] != "healthy":
                print(f"  - {component['name']}: {component['message']}")
```

### Kubernetes Liveness Probe

```yaml
livenessProbe:
  httpGet:
    path: /api/v1/system/health
    port: 8999
  initialDelaySeconds: 10
  periodSeconds: 30
```

### Admin Dashboard Integration

```javascript
async function loadDiagnostics() {
  const response = await fetch('/api/v1/system/diagnostics');
  const data = await response.json();

  // Update dashboard
  updateHealthIndicator(data.health.status);
  updateResourceGauges(data.resources);
  updateProviderList(data.providers);
}
```

### Troubleshooting Script

```bash
#!/bin/bash
echo "=== FlowMason Diagnostics ==="

# Health
echo "\nHealth Status:"
curl -s http://localhost:8999/api/v1/system/health | jq '.status, .components'

# Database
echo "\nDatabase:"
curl -s http://localhost:8999/api/v1/system/database | jq '.'

# Providers
echo "\nProviders:"
curl -s http://localhost:8999/api/v1/system/providers | jq '.[] | select(.configured == true)'

# Recent errors
echo "\nRecent Errors:"
curl -s "http://localhost:8999/api/v1/system/logs/recent?level=ERROR&limit=5" | jq '.logs'
```

## Environment Variables

| Variable | Description | Default |
|----------|-------------|---------|
| `FLOWMASON_ENV` | Environment (development/staging/production) | development |
| `FLOWMASON_DEFAULT_PROVIDER` | Default LLM provider | anthropic |
| `FLOWMASON_SCHEDULER_ENABLED` | Enable cron scheduler | true |
| `FLOWMASON_DEBUG` | Enable debug mode | false |
| `FLOWMASON_LOG_LEVEL` | Log level | INFO |
| `FLOWMASON_CORS_ORIGINS` | CORS allowed origins | * |


---

## 06-studio/template-gallery.md

# Template Gallery

FlowMason Studio includes a built-in template gallery with starter pipelines for common use cases. Templates provide a quick way to get started with new pipelines.

## Overview

Templates are pre-built pipeline configurations that you can:
- Browse by category or search by keyword
- Preview to understand the pipeline structure
- Create new pipelines from with one click
- Customize after creation

## Browsing Templates

### List All Templates

```bash
curl http://localhost:8999/api/v1/gallery/templates
```

Response:
```json
[
  {
    "id": "blog-post-generator",
    "name": "Blog Post Generator",
    "description": "Generate well-structured blog posts on any topic",
    "category": "content",
    "tags": ["writing", "blog", "content-generation"],
    "difficulty": "beginner",
    "estimated_time": "5 minutes",
    "use_case": "Creating blog posts, articles, or long-form content"
  }
]
```

### Filter by Category

```bash
curl "http://localhost:8999/api/v1/gallery/templates?category=content"
```

### Filter by Difficulty

```bash
curl "http://localhost:8999/api/v1/gallery/templates?difficulty=beginner"
```

### Search Templates

```bash
curl "http://localhost:8999/api/v1/gallery/templates?search=code"
```

## Template Categories

### List Categories

```bash
curl http://localhost:8999/api/v1/gallery/templates/categories
```

Response:
```json
[
  {"name": "analysis", "count": 2},
  {"name": "automation", "count": 2},
  {"name": "content", "count": 2},
  {"name": "data", "count": 2},
  {"name": "development", "count": 2}
]
```

### Available Categories

| Category | Description |
|----------|-------------|
| `content` | Content generation (blog posts, emails) |
| `data` | Data processing and transformation |
| `analysis` | Text analysis (sentiment, summarization) |
| `automation` | API chains and webhook processing |
| `development` | Code review and explanation |

## Template Tags

List all available tags for filtering:

```bash
curl http://localhost:8999/api/v1/gallery/templates/tags
```

## Getting Template Details

### Full Template

```bash
curl http://localhost:8999/api/v1/gallery/templates/blog-post-generator
```

Response includes:
- Full pipeline definition with all stages
- Sample input for testing
- Documentation and prerequisites

### Preview Only

Get a simplified view of the pipeline structure:

```bash
curl http://localhost:8999/api/v1/gallery/templates/blog-post-generator/preview
```

Response:
```json
{
  "name": "Blog Post Generator",
  "description": "Generate a blog post with outline, draft, and review",
  "stages": [
    {"id": "outline", "component_type": "generator", "depends_on": []},
    {"id": "draft", "component_type": "generator", "depends_on": ["outline"]},
    {"id": "review", "component_type": "critic", "depends_on": ["draft"]}
  ],
  "input_schema": {...},
  "sample_input": {...}
}
```

## Creating Pipelines from Templates

Create a new pipeline from a template:

```bash
curl -X POST http://localhost:8999/api/v1/gallery/templates/blog-post-generator/create-pipeline \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Blog Pipeline",
    "description": "Custom blog post generator"
  }'
```

Response:
```json
{
  "pipeline_id": "abc123...",
  "name": "My Blog Pipeline",
  "message": "Pipeline created from template 'Blog Post Generator'"
}
```

The created pipeline is fully editable in Studio.

## Built-in Templates

### Content Templates

#### Blog Post Generator
- **ID**: `blog-post-generator`
- **Difficulty**: Beginner
- **Stages**: outline → draft → review
- **Use case**: Creating blog posts, articles, or long-form content

#### Professional Email Writer
- **ID**: `email-writer`
- **Difficulty**: Beginner
- **Stages**: write-email
- **Use case**: Writing business emails, follow-ups, or formal communications

### Data Templates

#### Document Data Extractor
- **ID**: `data-extractor`
- **Difficulty**: Intermediate
- **Stages**: extract → parse → validate
- **Use case**: Extracting specific information from documents, emails, or reports

#### CSV Data Transformer
- **ID**: `csv-transformer`
- **Difficulty**: Intermediate
- **Stages**: load → transform (foreach) → enrich-row
- **Use case**: Processing CSV files, adding computed fields, or enriching data

### Analysis Templates

#### Sentiment Analyzer
- **ID**: `sentiment-analyzer`
- **Difficulty**: Beginner
- **Stages**: analyze → parse
- **Use case**: Analyzing customer feedback, reviews, or social media posts

#### Smart Text Summarizer
- **ID**: `text-summarizer`
- **Difficulty**: Beginner
- **Stages**: summarize
- **Use case**: Summarizing articles, documents, or meeting notes

### Automation Templates

#### API Data Chain
- **ID**: `api-chain`
- **Difficulty**: Intermediate
- **Stages**: fetch-primary → transform → fetch-secondary
- **Use case**: Integrating multiple APIs in a single workflow

#### Webhook Processor
- **ID**: `webhook-processor`
- **Difficulty**: Intermediate
- **Stages**: validate → route → (process-order | process-support | log-unknown)
- **Use case**: Processing webhooks from external services

### Development Templates

#### AI Code Reviewer
- **ID**: `code-reviewer`
- **Difficulty**: Intermediate
- **Stages**: analyze → summarize
- **Use case**: Automated code review for PRs or code audits

#### Code Explainer
- **ID**: `code-explainer`
- **Difficulty**: Beginner
- **Stages**: explain
- **Use case**: Understanding unfamiliar code or creating documentation

## Difficulty Levels

| Level | Description |
|-------|-------------|
| `beginner` | Simple pipelines, easy to understand and modify |
| `intermediate` | Multiple stages with dependencies, some configuration needed |
| `advanced` | Complex workflows, requires understanding of advanced features |

## Template Structure

Each template includes:

| Field | Description |
|-------|-------------|
| `id` | Unique identifier |
| `name` | Display name |
| `description` | Short description |
| `category` | Category for organization |
| `tags` | Keywords for search |
| `difficulty` | beginner/intermediate/advanced |
| `estimated_time` | Approximate setup time |
| `use_case` | When to use this template |
| `pipeline` | Full pipeline definition |
| `sample_input` | Example input for testing |
| `documentation` | Detailed usage instructions |
| `prerequisites` | Required API keys or setup |

## Best Practices

1. **Start Simple**: Begin with beginner templates to learn the patterns
2. **Use Sample Input**: Test templates with provided sample input first
3. **Customize Gradually**: Make small changes and test after each modification
4. **Check Prerequisites**: Ensure you have required API keys configured
5. **Read Documentation**: Each template includes usage documentation


---

## 06-studio/versioning.md

# Pipeline Versioning

FlowMason Studio provides version control for pipelines, enabling you to track changes, compare versions, and restore previous states.

## Overview

Pipeline versioning allows you to:
- Create named snapshots of pipeline configurations
- Track who made changes and when
- Compare versions to see what changed
- Restore pipelines to any previous version
- Maintain audit trails for compliance

## Creating Versions

### Manual Snapshot

Create a version snapshot at any time:

```bash
curl -X POST http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Added input validation stage",
    "created_by": "developer@example.com"
  }'
```

Response:
```json
{
  "id": "version-abc123",
  "pipeline_id": "pipeline-xyz",
  "version": "1.2.0",
  "name": "data-processor",
  "created_at": "2024-01-15T10:30:00Z",
  "created_by": "developer@example.com",
  "message": "Added input validation stage",
  "changes_summary": "1 stage(s) added",
  "stages_added": ["validate-input"],
  "stages_removed": [],
  "stages_modified": []
}
```

### Automatic Versioning

Versions are automatically created when:
- A pipeline is published
- A restore operation is performed (saves current state first)

## Listing Versions

View all versions of a pipeline:

```bash
curl http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions
```

Response:
```json
{
  "versions": [
    {
      "id": "version-abc123",
      "version": "1.2.0",
      "message": "Added validation",
      "created_at": "2024-01-15T10:30:00Z",
      "changes_summary": "1 stage(s) added"
    },
    {
      "id": "version-xyz789",
      "version": "1.1.0",
      "message": "Initial version",
      "created_at": "2024-01-10T08:00:00Z",
      "changes_summary": null
    }
  ],
  "total": 2,
  "limit": 50,
  "offset": 0
}
```

## Getting Version Details

### By Version ID

```bash
curl http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions/{version_id}
```

### By Version Number

```bash
curl http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions/by-version/1.2.0
```

### Latest Version

```bash
curl http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions/latest
```

Response includes full pipeline configuration:
```json
{
  "id": "version-abc123",
  "version": "1.2.0",
  "name": "data-processor",
  "description": "Process incoming data",
  "stages": [
    {
      "id": "validate-input",
      "component_type": "schema_validate",
      "config": { ... }
    },
    {
      "id": "process-data",
      "component_type": "json_transform",
      "config": { ... }
    }
  ],
  "input_schema": { ... },
  "output_schema": { ... },
  "created_at": "2024-01-15T10:30:00Z"
}
```

## Comparing Versions

Compare two versions to see what changed:

```bash
curl http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions/{version_id_1}/compare/{version_id_2}
```

Response:
```json
{
  "version_1": {
    "id": "version-abc123",
    "version": "1.2.0",
    "created_at": "2024-01-15T10:30:00Z"
  },
  "version_2": {
    "id": "version-xyz789",
    "version": "1.1.0",
    "created_at": "2024-01-10T08:00:00Z"
  },
  "stages_added": ["validate-input"],
  "stages_removed": [],
  "stages_modified": ["process-data"],
  "summary": "1 stage(s) added, 1 stage(s) modified"
}
```

## Restoring Versions

Restore a pipeline to a previous version:

```bash
curl -X POST http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions/{version_id}/restore
```

Response:
```json
{
  "pipeline_id": "pipeline-xyz",
  "restored_from_version": "1.1.0",
  "new_version": "1.3.0",
  "message": "Successfully restored from version 1.1.0"
}
```

The restore operation:
1. Saves the current state as a new version (so nothing is lost)
2. Updates the pipeline with the restored version's configuration
3. Creates a new version recording the restore

## Deleting Versions

Delete a specific version:

```bash
curl -X DELETE http://localhost:8999/api/v1/pipelines/{pipeline_id}/versions/{version_id}
```

## Version Fields

| Field | Description |
|-------|-------------|
| `id` | Unique version identifier |
| `pipeline_id` | Parent pipeline ID |
| `version` | Semantic version (e.g., "1.2.0") |
| `name` | Pipeline name at time of snapshot |
| `description` | Pipeline description |
| `stages` | Full stage configuration |
| `input_schema` | Input schema at snapshot |
| `output_schema` | Output schema at snapshot |
| `created_at` | When version was created |
| `created_by` | User who created the version |
| `message` | Commit-style message |
| `is_published` | Whether pipeline was published |
| `parent_version_id` | Previous version (for lineage) |
| `changes_summary` | Human-readable change summary |
| `stages_added` | List of added stage IDs |
| `stages_removed` | List of removed stage IDs |
| `stages_modified` | List of modified stage IDs |

## Best Practices

1. **Write meaningful messages**: Describe what changed and why
2. **Version before major changes**: Create a snapshot before significant edits
3. **Use comparison for review**: Compare versions before restoring
4. **Track with created_by**: Pass user identity for audit trails
5. **Clean up old versions**: Delete obsolete versions to save storage

## Database Storage

Versions are stored in the `pipeline_versions` table with full pipeline snapshots. Each version contains:
- Complete stage configurations
- Schema definitions
- LLM settings
- Diff metadata for quick comparison

The versioning system supports both SQLite (development) and PostgreSQL (production).

## Integration with Pipeline Updates

The standard pipeline update flow:
1. Edit pipeline in Studio or VSCode
2. Create version snapshot with message
3. Continue editing or publish
4. Restore if needed

Versions preserve the complete pipeline state, making it safe to experiment with changes.


---

## 07-integrations/mcp-ai-generation.md

# MCP AI Generation Tools

FlowMason's MCP server includes AI generation tools that enable AI assistants (Claude, GPT, etc.) to create and manage pipelines programmatically.

## Overview

The MCP server exposes tools for:
- **Pipeline Creation**: Generate complete pipeline configurations
- **Stage Generation**: Create individual stage configurations
- **Validation**: Validate pipeline configs before saving
- **Suggestions**: Get pipeline structure suggestions from task descriptions

## Available Tools

### suggest_pipeline

Get AI-powered suggestions for building a pipeline.

**Parameters:**
- `task_description`: Natural language description of what you want to accomplish

**Example Usage:**
```
Tool: suggest_pipeline
Input: "I want to summarize news articles and filter out sports content"
```

**Output:**
```markdown
## Suggested Pipeline for: I want to summarize news articles...

### Recommended Components

**1. generator**
   Purpose: Generate summary
   Rationale: Use LLM to create a summary of the input

**2. filter**
   Purpose: Filter items based on criteria
   Rationale: Filter data to include only relevant items

### Example Pipeline Structure

{
  "name": "suggested-pipeline",
  "stages": [...]
}
```

### generate_stage

Generate a stage configuration for a specific component type.

**Parameters:**
- `stage_type`: Component type (e.g., "generator", "filter")
- `purpose`: What this stage should do
- `input_source`: Where to get input ("input" or "stages.<stage_id>")

**Example:**
```
Tool: generate_stage
Input: {
  "stage_type": "generator",
  "purpose": "summarize the article content",
  "input_source": "input"
}
```

**Output:**
```json
{
  "id": "generator-a1b2c3",
  "name": "summarize the article content",
  "component_type": "generator",
  "config": {
    "prompt": "Based on the following input, summarize the article content:\n\n{{input}}",
    "max_tokens": 1000,
    "temperature": 0.7
  }
}
```

### create_pipeline

Create a new pipeline from a specification.

**Parameters:**
- `name`: Pipeline name
- `description`: What the pipeline does
- `stages_json`: JSON array of stage objects
- `input_schema_json`: (optional) JSON Schema for inputs

**Example:**
```
Tool: create_pipeline
Input: {
  "name": "content-summarizer",
  "description": "Summarizes articles and extracts key points",
  "stages_json": "[{\"id\": \"summarize\", \"name\": \"Summarize\", \"component_type\": \"generator\", \"config\": {\"prompt\": \"Summarize: {{input.text}}\"}}]"
}
```

**Output:**
```
Pipeline created successfully!

**File:** /path/to/content-summarizer.pipeline.json
**Name:** content-summarizer
**Stages:** 1

Run with: `fm run /path/to/content-summarizer.pipeline.json`
```

### validate_pipeline_config

Validate a pipeline configuration before creating it.

**Parameters:**
- `pipeline_json`: Full pipeline JSON configuration

**Example:**
```
Tool: validate_pipeline_config
Input: {
  "pipeline_json": "{\"name\": \"test\", \"stages\": []}"
}
```

**Output:**
```markdown
## Validation Failed

**Errors:**
- Pipeline must have at least one stage

**Warnings:**
- Consider adding a 'description' field
- Consider adding a 'version' field
```

## Workflow Example

Here's a typical workflow for an AI assistant creating a pipeline:

### 1. Understand Available Components

```
Tool: list_components
```

### 2. Get Suggestions

```
Tool: suggest_pipeline
Input: "Create a content moderation pipeline that checks text for profanity and sentiment"
```

### 3. Generate Stage Configurations

```
Tool: generate_stage
Input: {
  "stage_type": "generator",
  "purpose": "analyze sentiment of the text",
  "input_source": "input"
}
```

### 4. Validate the Pipeline

```
Tool: validate_pipeline_config
Input: {
  "pipeline_json": "..."
}
```

### 5. Create the Pipeline

```
Tool: create_pipeline
Input: {
  "name": "content-moderation",
  "description": "Checks content for profanity and sentiment",
  "stages_json": "[...]"
}
```

## Stage Configuration Templates

### Generator Stage

```json
{
  "id": "generate-content",
  "name": "Generate Content",
  "component_type": "generator",
  "config": {
    "prompt": "Based on {{input.topic}}, write a blog post.",
    "max_tokens": 2000,
    "temperature": 0.7
  }
}
```

### Filter Stage

```json
{
  "id": "filter-results",
  "name": "Filter Results",
  "component_type": "filter",
  "config": {
    "items_path": "{{stages.fetch.output.items}}",
    "condition": "item.score > 0.5"
  },
  "depends_on": ["fetch"]
}
```

### JSON Transform Stage

```json
{
  "id": "transform-data",
  "name": "Transform Data",
  "component_type": "json_transform",
  "config": {
    "template": {
      "summary": "{{stages.summarize.output}}",
      "timestamp": "{{now()}}",
      "source": "{{input.source}}"
    }
  },
  "depends_on": ["summarize"]
}
```

### HTTP Request Stage

```json
{
  "id": "call-api",
  "name": "Call External API",
  "component_type": "http_request",
  "config": {
    "url": "https://api.example.com/analyze",
    "method": "POST",
    "headers": {
      "Content-Type": "application/json"
    },
    "body": "{{input}}"
  }
}
```

### Loop Stage

```json
{
  "id": "process-items",
  "name": "Process Each Item",
  "component_type": "loop",
  "config": {
    "items_path": "{{input.items}}",
    "max_iterations": 100,
    "body_stage": "process-single"
  }
}
```

## Best Practices for AI Generation

### 1. Use Descriptive Names

```json
{
  "id": "extract-key-points",
  "name": "Extract Key Points from Article"
}
```

### 2. Chain Stages with Dependencies

```json
{
  "id": "stage-2",
  "depends_on": ["stage-1"],
  "config": {
    "input": "{{stages.stage-1.output}}"
  }
}
```

### 3. Document Input Requirements

```json
{
  "input_schema": {
    "type": "object",
    "properties": {
      "text": {
        "type": "string",
        "description": "The text content to process"
      }
    },
    "required": ["text"]
  }
}
```

### 4. Validate Before Creating

Always call `validate_pipeline_config` before `create_pipeline` to catch errors early.

### 5. Use Appropriate Components

| Task | Recommended Component |
|------|----------------------|
| Generate text | generator |
| Filter data | filter |
| Transform structure | json_transform |
| Make API calls | http_request |
| Iterate over items | loop |
| Evaluate content | critic |
| Select items | selector |

## Integration with AI Assistants

### Claude Desktop

Add to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "flowmason": {
      "command": "fm",
      "args": ["mcp", "serve"]
    }
  }
}
```

### Usage in Conversation

```
User: Create a pipeline that summarizes news articles

Claude: I'll create a summarization pipeline for you.

[Uses suggest_pipeline to understand structure]
[Uses generate_stage to create each stage]
[Uses validate_pipeline_config to check]
[Uses create_pipeline to save]

I've created your pipeline at news-summarizer.pipeline.json.
You can run it with: fm run news-summarizer.pipeline.json
```

## Error Handling

The tools provide helpful error messages:

```
Tool: create_pipeline
Error: "Stage 1 missing required 'id' field"
```

```
Tool: validate_pipeline_config
Warning: "Stage 'transform': consider adding 'name' for clarity"
```

Use validation feedback to iteratively improve the pipeline configuration before saving.


---

## 07-integrations/opentelemetry.md

# OpenTelemetry Integration

FlowMason provides native OpenTelemetry integration for distributed tracing of pipeline executions.

## Overview

The telemetry module enables:
- **Distributed Tracing**: Track pipeline executions across services
- **Stage-Level Visibility**: See timing and status of each stage
- **LLM Call Tracking**: Monitor LLM API calls with token counts
- **Multiple Exporters**: Send traces to Jaeger, Zipkin, OTLP, or console

## Installation

Install OpenTelemetry dependencies:

```bash
# Core SDK
pip install opentelemetry-api opentelemetry-sdk

# Exporters (install as needed)
pip install opentelemetry-exporter-otlp          # OTLP/gRPC
pip install opentelemetry-exporter-otlp-proto-http  # OTLP/HTTP
pip install opentelemetry-exporter-jaeger        # Jaeger
pip install opentelemetry-exporter-zipkin        # Zipkin
```

## Quick Start

```python
from flowmason_core.telemetry import (
    configure_tracing,
    get_tracer,
    TracingConfig,
    configure_console_exporter,
)

# Configure tracing
config = TracingConfig(
    service_name="my-pipeline-service",
    environment="production",
)
tracer = configure_tracing(config)

# Add console exporter for development
exporter = configure_console_exporter()
if exporter:
    tracer.add_exporter(exporter)

# Trace a pipeline execution
with tracer.start_pipeline_span("my-pipeline", pipeline_id="123") as span:
    # Execute stages
    with tracer.start_stage_span("stage-1", component_type="generator") as stage_span:
        result = execute_stage()
        if stage_span:
            stage_span.set_attribute("output.tokens", 150)
```

## Configuration

### TracingConfig Options

```python
from flowmason_core.telemetry import TracingConfig

config = TracingConfig(
    # Service identification
    service_name="flowmason",           # Service name in traces
    service_version="1.0.0",            # Service version
    environment="production",           # deployment environment

    # Feature flags
    enabled=True,                       # Enable/disable tracing
    trace_llm_calls=True,               # Trace LLM API calls
    trace_http_requests=True,           # Trace HTTP requests
    include_input_output=False,         # Include I/O in traces (may be sensitive)

    # Additional attributes
    resource_attributes={
        "team": "ml-platform",
        "region": "us-west-2",
    },
)
```

### Environment Variables

Configure via environment variables:

```bash
# Service info
export OTEL_SERVICE_NAME="my-service"
export OTEL_ENVIRONMENT="production"

# Enable/disable
export OTEL_TRACING_ENABLED="true"

# Exporter configuration
export OTEL_EXPORTER_TYPE="otlp"  # console, otlp, jaeger, zipkin
export OTEL_EXPORTER_OTLP_ENDPOINT="http://otel-collector:4317"
```

## Exporters

### Console Exporter (Development)

```python
from flowmason_core.telemetry import get_tracer, configure_console_exporter

tracer = get_tracer()
exporter = configure_console_exporter()
if exporter:
    tracer.add_exporter(exporter)
```

### OTLP Exporter (Production)

Send traces to OpenTelemetry Collector:

```python
from flowmason_core.telemetry import get_tracer, configure_otlp_exporter

tracer = get_tracer()
exporter = configure_otlp_exporter(
    endpoint="http://otel-collector:4317",
    headers={"Authorization": "Bearer token"},
    insecure=False,
)
if exporter:
    tracer.add_exporter(exporter)
```

### Jaeger Exporter

Send traces directly to Jaeger:

```python
from flowmason_core.telemetry import get_tracer, configure_jaeger_exporter

tracer = get_tracer()
exporter = configure_jaeger_exporter(
    agent_host_name="jaeger",
    agent_port=6831,
    # Or use HTTP collector
    # collector_endpoint="http://jaeger:14268/api/traces",
)
if exporter:
    tracer.add_exporter(exporter)
```

### Auto-Configure from Environment

```python
from flowmason_core.telemetry.exporters import configure_from_env

exporter = configure_from_env()
if exporter:
    get_tracer().add_exporter(exporter)
```

## Instrumentation

### Using Decorators

```python
from flowmason_core.telemetry import trace_pipeline, trace_stage

@trace_pipeline("content-generator")
async def run_content_pipeline(input_data: dict) -> dict:
    result = await generate_content(input_data)
    return result

@trace_stage("generate", component_type="generator")
async def generate_content(input_data: dict) -> str:
    # LLM call here
    return content
```

### Using Context Managers

```python
from flowmason_core.telemetry import instrument_pipeline, instrument_stage

with instrument_pipeline("pipeline-123", "my-pipeline", run_id="run-456") as span:
    if span:
        span.set_attribute("custom.attribute", "value")

    with instrument_stage("stage-1", "extract", "extractor") as stage_span:
        result = await execute_stage()
        if stage_span:
            stage_span.set_attribute("records.count", len(result))
```

### Using PipelineInstrumentation Class

```python
from flowmason_core.telemetry import PipelineInstrumentation

instrumentation = PipelineInstrumentation(
    pipeline_id="123",
    pipeline_name="my-pipeline",
    run_id="run-456",
)

with instrumentation.pipeline_span() as pipeline_span:
    for stage in stages:
        with instrumentation.stage_span(
            stage.id, stage.name, stage.component_type
        ) as stage_span:
            try:
                start = time.time()
                result = await execute_stage(stage)
                duration = int((time.time() - start) * 1000)

                instrumentation.record_stage_success(
                    stage_span,
                    duration_ms=duration,
                    output_tokens=result.tokens,
                )
            except Exception as e:
                instrumentation.record_stage_failure(
                    stage_span, e, duration_ms=duration
                )
                raise

    instrumentation.record_pipeline_complete(
        pipeline_span,
        success=True,
        total_duration_ms=total_duration,
        total_tokens=total_tokens,
    )
```

## Span Attributes

### Pipeline Spans

| Attribute | Type | Description |
|-----------|------|-------------|
| `flowmason.pipeline.name` | string | Pipeline name |
| `flowmason.pipeline.id` | string | Pipeline ID |
| `flowmason.run.id` | string | Run ID |
| `flowmason.pipeline.duration_ms` | int | Total duration |
| `flowmason.pipeline.success` | bool | Success status |
| `flowmason.pipeline.stage_count` | int | Number of stages |
| `flowmason.pipeline.total_tokens` | int | Total tokens used |
| `flowmason.pipeline.total_cost_usd` | float | Total cost |

### Stage Spans

| Attribute | Type | Description |
|-----------|------|-------------|
| `flowmason.stage.id` | string | Stage ID |
| `flowmason.stage.name` | string | Stage name |
| `flowmason.stage.component_type` | string | Component type |
| `flowmason.stage.duration_ms` | int | Stage duration |
| `flowmason.stage.success` | bool | Success status |
| `flowmason.stage.output_tokens` | int | Output tokens |
| `flowmason.stage.cost_usd` | float | Stage cost |

### LLM Call Spans

| Attribute | Type | Description |
|-----------|------|-------------|
| `flowmason.llm.provider` | string | Provider name |
| `flowmason.llm.model` | string | Model name |
| `flowmason.llm.operation` | string | Operation type |
| `flowmason.llm.input_tokens` | int | Input tokens |
| `flowmason.llm.output_tokens` | int | Output tokens |

## LLM Call Tracing

```python
tracer = get_tracer()

with tracer.start_pipeline_span("my-pipeline") as pipeline_span:
    with tracer.start_stage_span("generate") as stage_span:
        # Trace the LLM call
        with tracer.start_llm_span(
            provider="openai",
            model="gpt-4",
            operation="generate",
        ) as llm_span:
            response = await openai.chat.completions.create(...)

            if llm_span:
                llm_span.set_attribute("llm.input_tokens", response.usage.prompt_tokens)
                llm_span.set_attribute("llm.output_tokens", response.usage.completion_tokens)
```

## Distributed Tracing

### Propagating Context

```python
tracer = get_tracer()

# Inject context into headers for outgoing requests
headers = {}
tracer.inject_context(headers)
# headers now contains 'traceparent' and 'tracestate'

# Make HTTP request with propagated context
response = await httpx.post(url, headers=headers)
```

### Extracting Context

```python
from fastapi import Request

@app.post("/run")
async def run_pipeline(request: Request):
    tracer = get_tracer()

    # Extract context from incoming request headers
    context = tracer.extract_context(dict(request.headers))

    # Continue trace with extracted context
    with tracer.start_pipeline_span(
        "my-pipeline",
        parent=context,  # Link to parent span
    ) as span:
        # Execute pipeline
        pass
```

## Docker Compose with Jaeger

```yaml
version: '3.8'

services:
  flowmason:
    build: .
    environment:
      - OTEL_SERVICE_NAME=flowmason
      - OTEL_EXPORTER_TYPE=jaeger
      - OTEL_EXPORTER_JAEGER_AGENT_HOST=jaeger
      - OTEL_EXPORTER_JAEGER_AGENT_PORT=6831

  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686"  # Jaeger UI
      - "6831:6831/udp"  # Jaeger agent
```

Access Jaeger UI at http://localhost:16686

## Best Practices

1. **Use Meaningful Span Names**: Include pipeline/stage names for easy identification

2. **Add Custom Attributes**: Include business-relevant data like user IDs, request IDs

3. **Handle Errors Properly**: Always record exceptions for debugging

4. **Use Sampling in Production**: Reduce overhead with sampling:
   ```python
   config = TracingConfig(sampling_ratio=0.1)  # Sample 10%
   ```

5. **Protect Sensitive Data**: Disable `include_input_output` for sensitive pipelines

6. **Set Up Alerts**: Configure alerts in your observability platform for:
   - High latency pipelines
   - Frequent stage failures
   - LLM API errors


---

## 07-integrations/remote-registry.md

# Remote Registry

FlowMason supports remote package registries for sharing and distributing components across teams and projects.

## Overview

The remote registry system enables:
- **Package Discovery**: Search for packages across multiple registries
- **Version Management**: Install specific versions with dependency resolution
- **Package Distribution**: Publish packages to registries
- **Multi-Registry Support**: Configure multiple registries with priorities
- **Local Caching**: Downloaded packages are cached locally

## CLI Commands

### Managing Registries

```bash
# List configured registries
fm registry list

# Add a new registry
fm registry add my-registry https://registry.example.com

# Add with authentication
fm registry add private-registry https://registry.example.com --token $TOKEN

# Set as default
fm registry add my-registry https://registry.example.com --default

# Remove a registry
fm registry remove my-registry

# Set default registry
fm registry set-default my-registry
```

### Searching Packages

```bash
# Search all registries
fm search summarizer

# Search specific registry
fm search summarizer --registry my-registry

# Filter by category
fm search filter --category transformers

# Output as JSON
fm search summarizer --json
```

### Installing Packages

```bash
# Install latest version
fm install my-package

# Install specific version
fm install my-package --version 1.2.0

# Install from specific registry
fm install my-package --registry my-registry

# Install to custom directory
fm install my-package --dir ./packages
```

### Publishing Packages

```bash
# Publish to default registry
fm publish my-package-1.0.0.fmpkg

# Publish to specific registry
fm publish my-package-1.0.0.fmpkg --registry my-registry
```

### Cache Management

```bash
# View cache stats
fm registry cache

# Clear all cached packages
fm registry cache --clear

# Clear packages older than 30 days
fm registry cache --clear --older-than 30
```

## Configuration

Registries are configured in `~/.flowmason/registries.json`:

```json
{
  "registries": [
    {
      "name": "local",
      "url": "http://localhost:8999",
      "priority": 50,
      "enabled": true,
      "is_default": true,
      "can_publish": true,
      "requires_auth": false,
      "description": "Local FlowMason Studio"
    },
    {
      "name": "company",
      "url": "https://registry.company.com",
      "auth_token": "...",
      "priority": 100,
      "enabled": true,
      "can_publish": true,
      "requires_auth": true
    }
  ]
}
```

### Configuration Options

| Option | Description |
|--------|-------------|
| `name` | Unique identifier for the registry |
| `url` | Base URL of the registry |
| `auth_token` | Optional authentication token |
| `priority` | Lower = higher priority (default: 100) |
| `enabled` | Whether the registry is active |
| `is_default` | Use as default for operations |
| `can_publish` | Whether publishing is allowed |
| `requires_auth` | Whether authentication is required |

## Running a Registry Server

FlowMason Studio can act as a registry server. When Studio is running, it exposes registry API endpoints.

### Start Studio as Registry

```bash
fm studio start
```

The registry API is available at `http://localhost:8999/api/v1/registry/`.

### Registry API Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/registry/health` | GET | Check registry health |
| `/registry/packages/search` | GET | Search packages |
| `/registry/packages/{name}` | GET | Get package info |
| `/registry/packages/{name}/{version}` | GET | Get specific version |
| `/registry/packages/{name}/versions` | GET | List all versions |
| `/registry/packages/{name}/{version}/download` | GET | Download package |
| `/registry/packages/upload` | POST | Upload package |
| `/registry/categories` | GET | List categories |
| `/registry/stats` | GET | Registry statistics |

## Python API

```python
from flowmason_core.registry import (
    get_remote_registry,
    RemoteRegistryClient,
)

# Get the global client
client = get_remote_registry()

# Add a registry
client.add_registry(
    name="my-registry",
    url="https://registry.example.com",
    auth_token="...",
    priority=100,
)

# Search for packages
results = client.search("summarizer")
for pkg in results.packages:
    print(f"{pkg.name} v{pkg.version}: {pkg.description}")

# Get package info
pkg = client.get_package("my-package")
print(f"Components: {pkg.components}")

# Download and install
install_path = client.install("my-package", version="1.0.0")
print(f"Installed to: {install_path}")

# Publish a package
from pathlib import Path
pkg_info = client.publish(Path("my-package-1.0.0.fmpkg"))
print(f"Published: {pkg_info.name}@{pkg_info.version}")
```

## Package Verification

Downloaded packages are verified using SHA256 checksums:

```python
# Downloads automatically verify checksum
client.download("my-package", verify=True)

# Skip verification (not recommended)
client.download("my-package", verify=False)
```

## Multi-Registry Resolution

When searching or installing, registries are queried in priority order:

1. Registries with lower priority numbers are checked first
2. First match is used for installation
3. Search aggregates results from all enabled registries

```python
# Configure priorities
client.add_registry("primary", "https://primary.example.com", priority=10)
client.add_registry("fallback", "https://fallback.example.com", priority=100)

# primary will be checked first
client.install("my-package")
```

## Authentication

### Token-Based Auth

```bash
# Add registry with token
fm registry add private https://registry.example.com --token $MY_TOKEN
```

### Environment Variables

You can also set tokens via environment variables:

```bash
export FLOWMASON_REGISTRY_TOKEN=your-token
```

## Best Practices

1. **Use Specific Versions**: Always specify versions in production
2. **Private Registries**: Use authentication for private packages
3. **Cache Management**: Periodically clean old cached packages
4. **Checksum Verification**: Always verify package checksums
5. **Priority Planning**: Set priorities to control resolution order

## Troubleshooting

### Connection Issues

```bash
# Check registry health
curl https://registry.example.com/api/v1/registry/health
```

### Authentication Errors

```bash
# Verify token is set
fm registry list --all

# Re-add with correct token
fm registry remove my-registry
fm registry add my-registry https://... --token $TOKEN
```

### Package Not Found

```bash
# Check available versions
fm search my-package --json

# Try specific registry
fm install my-package --registry other-registry
```


---

## 07-integrations/vscode-mcp.md

# VSCode Extension MCP Integration

The FlowMason VSCode extension includes AI-assisted pipeline creation via MCP (Model Context Protocol) integration. This allows developers to describe what they want in natural language and have the extension generate pipeline configurations automatically.

## Features

### Create Pipeline with AI
Use natural language to describe your pipeline, and let AI generate the complete configuration.

**Command:** `FlowMason: Create Pipeline with AI` (Cmd+Shift+P)

**Workflow:**
1. Describe what you want (e.g., "Summarize articles and filter by sentiment")
2. Review suggested stages
3. Select which stages to include
4. Choose to accept or customize the generated configuration
5. Name your pipeline and save

### Get Pipeline Suggestions
Get AI-powered suggestions for building a pipeline without committing to creation.

**Command:** `FlowMason: Get Pipeline Suggestions`

**Usage:**
1. Describe your task
2. View suggested components and their purposes
3. See example pipeline structure in the output panel
4. Optionally proceed to create the pipeline

### Generate Stage with AI
Generate a single stage configuration for any component type.

**Command:** `FlowMason: Generate Stage with AI`

**Workflow:**
1. Select component type (generator, filter, json_transform, etc.)
2. Describe what the stage should do
3. Specify input source (pipeline input or previous stage output)
4. Review generated configuration in editor

### Validate Pipeline
Validate the currently open pipeline file for errors and warnings.

**Command:** `FlowMason: Validate Pipeline`

Available in the editor title bar for `.pipeline.json` files.

### Add AI-Generated Stage
Add an AI-generated stage to the currently open pipeline.

**Command:** `FlowMason: Add AI-Generated Stage`

**Workflow:**
1. Open a `.pipeline.json` file
2. Select component type
3. Describe stage purpose
4. Select input source from existing stages
5. Stage is automatically added to the pipeline

## Keyboard Shortcuts

| Action | Shortcut |
|--------|----------|
| Create Pipeline with AI | Cmd+Shift+P → "FlowMason: Create Pipeline with AI" |
| Validate Pipeline | Cmd+Shift+P → "FlowMason: Validate Pipeline" |

## Editor Title Bar Actions

When editing a `.pipeline.json` file, additional buttons appear in the editor title bar:

- **Add AI-Generated Stage** - Generate and add a new stage
- **Validate Pipeline** - Check for errors and warnings

## How It Works

The extension uses the MCP service to communicate with FlowMason Studio or provides local fallback functionality:

### With FlowMason Studio Running
- Fetches available components from the registry
- Validates against actual component schemas
- Accesses pipeline templates and examples

### Local Mode (Studio Not Running)
- Uses built-in component knowledge
- Generates reasonable default configurations
- Validates basic pipeline structure

## Configuration

The MCP integration uses the existing FlowMason settings:

```json
{
  "flowmason.studioUrl": "http://localhost:8999"
}
```

## Example Usage

### Creating a Content Processing Pipeline

1. Open Command Palette (Cmd+Shift+P)
2. Type "FlowMason: Create Pipeline with AI"
3. Enter description: "Fetch RSS feed, summarize each article, and filter by topic relevance"
4. Review suggested stages:
   - `http_request` - Fetch RSS feed
   - `loop` - Iterate over articles
   - `generator` - Summarize content
   - `filter` - Filter by relevance
5. Select all stages and accept
6. Name pipeline "rss-summarizer"
7. Pipeline is created and opened in editor

### Adding a Stage to Existing Pipeline

1. Open your `.pipeline.json` file
2. Click "Add AI-Generated Stage" in editor title bar
3. Select `filter` component
4. Describe: "filter out articles older than 7 days"
5. Select input source: `stages.fetch.output`
6. Stage is added with appropriate configuration

## Troubleshooting

### "Failed to get suggestions"
- Check if FlowMason Studio is running
- Verify `flowmason.studioUrl` setting is correct
- The extension will fall back to local mode automatically

### Generated Configuration Needs Adjustment
- Use "Customize" option to edit generated stages
- Generated prompts and configurations are starting points
- Adjust parameters based on your specific needs

### Validation Errors
- Run "FlowMason: Validate Pipeline" to see detailed errors
- Check the FlowMason output panel for full error messages
- Common issues: missing required fields, invalid stage IDs

## Best Practices

1. **Be Specific**: More detailed descriptions yield better suggestions
2. **Review Before Saving**: Always review generated configurations
3. **Use Validation**: Validate before running pipelines
4. **Iterate**: Use "Add AI-Generated Stage" to build incrementally
5. **Customize**: Treat generated config as a starting point

## API Integration

The extension exposes MCP functionality through the following internal service:

```typescript
interface MCPService {
  suggestPipeline(taskDescription: string): Promise<PipelineSuggestion>
  generateStage(stageType: string, purpose: string, inputSource: string): Promise<GeneratedStage>
  validatePipeline(pipelineJson: string): Promise<ValidationResult>
  createPipeline(name: string, description: string, stages: GeneratedStage[]): Promise<string>
}
```

This service can be used by other extension features or extensions that depend on FlowMason.


---

## 08-packaging-deployment/edge-deployment.md

# Edge Deployment

Run FlowMason pipelines on edge devices with offline-first execution and local LLM support.

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│                         CLOUD                                   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │  FlowMason Studio (Central)                              │   │
│  │  - Pipeline registry                                     │   │
│  │  - Execution history sync                                │   │
│  │  - Edge device management                                │   │
│  └────────────────────────┬────────────────────────────────┘   │
└───────────────────────────┼─────────────────────────────────────┘
                            │ Sync (when connected)
        ┌───────────────────┼───────────────────┐
        │                   │                   │
        ▼                   ▼                   ▼
┌───────────────┐   ┌───────────────┐   ┌───────────────┐
│  Edge Node 1  │   │  Edge Node 2  │   │  Edge Node 3  │
│  (Raspberry)  │   │  (Jetson)     │   │  (Industrial) │
│  ┌─────────┐  │   │  ┌─────────┐  │   │  ┌─────────┐  │
│  │Pipeline │  │   │  │Pipeline │  │   │  │Pipeline │  │
│  │Cache    │  │   │  │Cache    │  │   │  │Cache    │  │
│  └─────────┘  │   │  └─────────┘  │   │  └─────────┘  │
└───────────────┘   └───────────────┘   └───────────────┘
```

## Installation

### Python Package

```bash
pip install flowmason-edge
```

### Docker (ARM64)

```bash
docker pull flowmason/edge:latest-arm64
docker run -d --name flowmason-edge \
  -v /var/flowmason:/var/flowmason \
  -e CLOUD_URL=https://studio.flowmason.io \
  -e API_KEY=your-api-key \
  flowmason/edge:latest-arm64
```

## Configuration

### EdgeConfig

```python
from flowmason_edge import EdgeConfig, create_runtime

config = EdgeConfig(
    # Storage directories
    data_dir="/var/flowmason/edge",
    pipeline_cache_dir="/var/flowmason/pipelines",
    model_cache_dir="/var/flowmason/models",
    result_store_dir="/var/flowmason/results",

    # Cloud connection
    cloud_url="https://studio.flowmason.io",
    api_key="your-api-key",

    # Execution limits
    max_concurrent=2,
    execution_timeout=300,

    # Cache settings
    pipeline_cache_size_mb=100,
    pipeline_ttl_days=30,
    model_cache_size_gb=50,
    result_retention_days=30,

    # Sync settings
    sync_interval=60,
    auto_sync=True,

    # LLM settings
    llm_backend="ollama",  # or "llamacpp"
    llm_model="llama2",
    llm_base_url="http://localhost:11434"
)

# Create runtime
runtime = await create_runtime(config)
```

## Edge Executor

The `EdgeExecutor` runs pipelines locally with offline support.

```python
from flowmason_edge import EdgeExecutor, EdgeConfig

config = EdgeConfig(data_dir="/var/flowmason/edge")
executor = EdgeExecutor(config)

# Execute a pipeline
result = await executor.execute(
    pipeline_id="data-processor",
    inputs={"sensor_data": [1, 2, 3]}
)

print(f"Status: {result.status}")
print(f"Output: {result.output}")
print(f"Duration: {result.duration_ms}ms")
```

## Local LLM Support

### Ollama Adapter

```python
from flowmason_edge.adapters import OllamaAdapter

adapter = OllamaAdapter(
    base_url="http://localhost:11434",
    model="llama2"
)

# Generate text
response = await adapter.generate(
    prompt="Summarize: ...",
    temperature=0.7,
    max_tokens=500
)
```

### LlamaCpp Adapter

```python
from flowmason_edge.adapters import LlamaCppAdapter

adapter = LlamaCppAdapter(
    model_path="/models/llama-2-7b.gguf",
    n_ctx=2048,
    n_threads=4
)

response = await adapter.generate(prompt="...")
```

## Caching

### Pipeline Cache

Pipelines are cached locally for offline execution.

```python
from flowmason_edge.cache import PipelineCache

cache = PipelineCache(
    cache_dir="/var/flowmason/pipelines",
    max_size_mb=100,
    ttl_days=30
)

# Cache a pipeline
await cache.store("my-pipeline", pipeline_config)

# Retrieve cached pipeline
pipeline = await cache.get("my-pipeline")

# Check if cached
exists = await cache.exists("my-pipeline")

# Clear old entries
await cache.cleanup()
```

### Model Cache

LLM models are cached locally.

```python
from flowmason_edge.cache import ModelCache

cache = ModelCache(
    cache_dir="/var/flowmason/models",
    max_size_gb=50
)

# Download and cache model
await cache.ensure_model("llama2")

# Get model path
path = cache.get_model_path("llama2")
```

### Result Store

Execution results are stored for sync.

```python
from flowmason_edge.cache import ResultStore

store = ResultStore(
    store_dir="/var/flowmason/results",
    retention_days=30
)

# Store result
await store.save(run_id, result)

# Get pending results (not yet synced)
pending = await store.get_pending()

# Mark as synced
await store.mark_synced(run_id)
```

## Cloud Sync

### SyncManager

Synchronizes with the cloud when connectivity is available.

```python
from flowmason_edge import SyncManager

sync = SyncManager(
    cloud_url="https://studio.flowmason.io",
    api_key="your-api-key",
    sync_interval=60,
    ping_interval=30
)

# Check connection status
status = sync.status  # SyncStatus.ONLINE or SyncStatus.OFFLINE

# Manual sync
await sync.sync_results()
await sync.sync_pipelines()

# Set status callback
sync.on_status_change = lambda status: print(f"Status: {status}")

# Start background sync
await sync.start()

# Stop sync
await sync.stop()
```

## CLI Commands

```bash
# Start edge runtime
fm-edge start

# Check status
fm-edge status

# Run pipeline locally
fm-edge run my-pipeline --input data.json

# Sync with cloud
fm-edge sync

# List cached pipelines
fm-edge list

# Clear cache
fm-edge clear-cache --pipelines --models

# Configure
fm-edge config set cloud_url https://studio.flowmason.io
fm-edge config set api_key your-key
```

## HTTP API

The edge runtime exposes a local HTTP API:

```bash
# Start server
fm-edge serve --port 8080
```

### Endpoints

```
POST /run/{pipeline_id}     # Execute pipeline
GET  /status/{run_id}       # Get run status
GET  /pipelines             # List cached pipelines
GET  /health                # Health check
POST /sync                  # Trigger sync
```

## Environment Variables

```bash
FLOWMASON_EDGE_DATA_DIR=/var/flowmason/edge
FLOWMASON_CLOUD_URL=https://studio.flowmason.io
FLOWMASON_API_KEY=your-api-key
FLOWMASON_LLM_BACKEND=ollama
FLOWMASON_LLM_MODEL=llama2
OLLAMA_HOST=http://localhost:11434
```

## Resource Constraints

For resource-constrained devices:

```python
config = EdgeConfig(
    max_concurrent=1,           # Single execution
    execution_timeout=120,      # 2 minute timeout
    pipeline_cache_size_mb=50,  # Smaller cache
    model_cache_size_gb=10,     # Smaller model cache
)
```

## Best Practices

1. **Pre-cache Pipelines**: Download pipelines before going offline
2. **Use Quantized Models**: Use GGUF quantized models for smaller footprint
3. **Set Retention Limits**: Configure result retention to prevent disk fill
4. **Monitor Sync Status**: Alert on extended offline periods
5. **Test Offline**: Verify pipelines work without cloud connectivity


---

## 08-packaging-deployment/federation.md

# Federated Execution

Distribute pipeline execution across multiple clouds and regions for improved performance, data locality, and resilience.

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│  Pipeline: global-data-processor                                │
│                                                                 │
│  ┌─────────┐     ┌─────────────────────────────────┐           │
│  │ ingest  │────▶│     PARALLEL FEDERATION         │           │
│  │ (local) │     │  ┌───────┐ ┌───────┐ ┌───────┐ │           │
│  └─────────┘     │  │US-EAST│ │EU-WEST│ │AP-EAST│ │           │
│                  │  │process│ │process│ │process│ │           │
│                  │  └───┬───┘ └───┬───┘ └───┬───┘ │           │
│                  └──────┼─────────┼─────────┼─────┘           │
│                         └─────────┼─────────┘                  │
│                                   ▼                            │
│                            ┌───────────┐                       │
│                            │  aggregate │                       │
│                            │  (local)   │                       │
│                            └───────────┘                       │
└─────────────────────────────────────────────────────────────────┘
```

## Configuration

### Region Configuration

```python
from flowmason_core.federation import (
    FederationConfig, RegionConfig, FederatedStageConfig,
    FederationStrategy, AggregationStrategy
)

# Define regions
us_east = RegionConfig(
    name="us-east-1",
    endpoint="https://us-east.flowmason.io",
    api_key="us-east-key",
    priority=1,
    weight=1.0,
    max_concurrent=10,
    timeout_seconds=300,
    tags=["gpu", "high-memory"],
    latitude=37.7749,
    longitude=-122.4194,
    cost_per_execution=0.01,
    cost_per_token=0.00001
)

eu_west = RegionConfig(
    name="eu-west-1",
    endpoint="https://eu-west.flowmason.io",
    api_key="eu-west-key",
    priority=2,
    latitude=51.5074,
    longitude=-0.1278
)

# Create federation config
config = FederationConfig(
    regions=[us_east, eu_west],
    default_strategy=FederationStrategy.NEAREST
)
```

### Federated Stage Configuration

Configure federation at the stage level in your pipeline:

```json
{
  "stages": [
    {
      "id": "process-data",
      "type": "transformer",
      "federation": {
        "strategy": "parallel",
        "regions": ["us-east-1", "eu-west-1", "ap-northeast-1"],
        "data_locality": true,
        "aggregation": "merge"
      }
    }
  ]
}
```

## Federation Strategies

### FederationStrategy

| Strategy | Description |
|----------|-------------|
| `PARALLEL` | Execute on all regions simultaneously |
| `SEQUENTIAL` | Execute on regions in order |
| `NEAREST` | Execute on geographically nearest region |
| `ROUND_ROBIN` | Distribute across regions evenly |
| `LEAST_LOADED` | Route to region with lowest load |
| `COST_OPTIMIZED` | Route to cheapest available region |

### Python API

```python
from flowmason_core.federation import FederatedStageConfig, FederationStrategy

stage_config = FederatedStageConfig(
    strategy=FederationStrategy.PARALLEL,
    regions=["us-east-1", "eu-west-1"],
    data_locality=True,
    aggregation=AggregationStrategy.MERGE,
    timeout_seconds=300,
    retry_on_failure=True,
    fallback_region="us-east-1"
)
```

## Aggregation Strategies

When executing in parallel, results must be aggregated:

| Strategy | Description |
|----------|-------------|
| `MERGE` | Merge all results into one object |
| `REDUCE` | Apply reduce function to results |
| `FIRST` | Return first successful result |
| `ALL` | Return array of all results |
| `MAJORITY` | Return most common result |

## FederationCoordinator

The coordinator orchestrates federated execution.

```python
from flowmason_core.federation import FederationCoordinator

coordinator = FederationCoordinator(config)

# Execute federated stage
result = await coordinator.execute_federated(
    stage_id="process-data",
    stage_config=stage_config,
    inputs={"data": large_dataset}
)

print(f"Results from {len(result.region_results)} regions")
print(f"Aggregated output: {result.aggregated}")
```

## RemoteExecutor

Executes stages on remote regions.

```python
from flowmason_core.federation import RemoteExecutor

executor = RemoteExecutor(config)

# Execute on specific region
result = await executor.execute(
    region="us-east-1",
    stage_id="process",
    inputs={"data": data}
)

# Execute on multiple regions
results = await executor.execute_parallel(
    regions=["us-east-1", "eu-west-1"],
    stage_id="process",
    inputs={"data": data}
)
```

## DataRouter

Routes data to optimal regions based on locality.

```python
from flowmason_core.federation import DataRouter

router = DataRouter(config)

# Get optimal region for data source
region = router.get_optimal_region(
    data_location={"lat": 40.7128, "lon": -74.0060}  # New York
)
print(f"Optimal region: {region}")  # us-east-1

# Route data to regions
routing = router.route_data(
    data=large_dataset,
    strategy=FederationStrategy.NEAREST,
    source_location={"lat": 40.7128, "lon": -74.0060}
)
```

## Pipeline Configuration

Enable federation in your pipeline.json:

```json
{
  "id": "global-analytics",
  "name": "Global Analytics Pipeline",
  "federation": {
    "enabled": true,
    "default_strategy": "nearest"
  },
  "stages": [
    {
      "id": "collect",
      "type": "http_request",
      "config": { "url": "{{input.data_url}}" }
    },
    {
      "id": "process",
      "type": "json_transform",
      "depends_on": ["collect"],
      "federation": {
        "strategy": "parallel",
        "regions": ["us-east-1", "eu-west-1", "ap-northeast-1"],
        "aggregation": "merge"
      }
    },
    {
      "id": "store",
      "type": "database_write",
      "depends_on": ["process"]
    }
  ]
}
```

## Monitoring

### Federation Metrics

```python
# Get federation statistics
stats = coordinator.get_stats()

print(f"Total executions: {stats.total_executions}")
print(f"Success rate: {stats.success_rate}%")
print(f"Average latency: {stats.avg_latency_ms}ms")

# Per-region stats
for region, region_stats in stats.by_region.items():
    print(f"{region}: {region_stats.success_rate}% success")
```

### Health Checks

```python
# Check region health
health = await coordinator.check_health()

for region, status in health.items():
    print(f"{region}: {'healthy' if status.healthy else 'unhealthy'}")
    print(f"  Latency: {status.latency_ms}ms")
    print(f"  Load: {status.current_load}/{status.max_concurrent}")
```

## Error Handling

### Failover

```python
stage_config = FederatedStageConfig(
    strategy=FederationStrategy.NEAREST,
    regions=["us-east-1", "eu-west-1"],
    retry_on_failure=True,
    max_retries=3,
    fallback_region="eu-west-1"
)
```

### Partial Failures

```python
result = await coordinator.execute_federated(...)

if result.has_partial_failure:
    print(f"Failed regions: {result.failed_regions}")
    print(f"Successful regions: {result.successful_regions}")
```

## Best Practices

1. **Use Data Locality**: Enable `data_locality` to reduce data transfer
2. **Set Timeouts**: Configure appropriate timeouts per region
3. **Monitor Costs**: Track cost_per_execution for optimization
4. **Configure Fallbacks**: Always set fallback regions
5. **Test Failover**: Regularly test region failover scenarios
6. **Balance Load**: Use ROUND_ROBIN or LEAST_LOADED for even distribution


---

## 08-packaging-deployment/kubernetes.md

# Kubernetes Deployment

Deploy and manage FlowMason pipelines as Kubernetes resources using Custom Resource Definitions (CRDs).

## Overview

```yaml
apiVersion: flowmason.io/v1
kind: Pipeline
metadata:
  name: data-processor
  namespace: production
spec:
  stages:
    - id: fetch
      componentType: http_request
      config:
        url: https://api.example.com/data
    - id: process
      componentType: json_transform
      dependsOn: [fetch]
  schedule: "0 * * * *"
  resources:
    requests:
      memory: "256Mi"
      cpu: "100m"
```

## Custom Resource Definitions

### Pipeline CRD

The Pipeline CRD defines a pipeline configuration that can be scheduled and managed by Kubernetes.

```python
from flowmason_core.kubernetes import Pipeline, PipelineSpec, StageSpec

# Create a Pipeline resource
pipeline = Pipeline(
    api_version="flowmason.io/v1",
    kind="Pipeline",
    metadata={
        "name": "data-processor",
        "namespace": "production"
    },
    spec=PipelineSpec(
        stages=[
            StageSpec(
                id="fetch",
                componentType="http_request",
                config={"url": "https://api.example.com"}
            ),
            StageSpec(
                id="process",
                componentType="json_transform",
                dependsOn=["fetch"]
            )
        ],
        schedule="0 * * * *",
        resources={
            "requests": {"memory": "256Mi", "cpu": "100m"},
            "limits": {"memory": "512Mi", "cpu": "500m"}
        }
    )
)
```

### PipelineRun CRD

The PipelineRun CRD represents an individual execution of a pipeline.

```python
from flowmason_core.kubernetes import PipelineRun, PipelineRunSpec

# Create a PipelineRun
run = PipelineRun(
    api_version="flowmason.io/v1",
    kind="PipelineRun",
    metadata={
        "name": "data-processor-run-001",
        "namespace": "production"
    },
    spec=PipelineRunSpec(
        pipeline_ref="data-processor",
        inputs={"date": "2025-12-14"}
    )
)
```

## Pipeline Spec Fields

| Field | Type | Description |
|-------|------|-------------|
| `stages` | `List[StageSpec]` | Pipeline stages (required) |
| `source` | `Dict` | ConfigMap reference for pipeline config |
| `schedule` | `str` | Cron expression for scheduling |
| `triggers` | `Dict` | Event triggers configuration |
| `resources` | `Dict` | Resource requests and limits |
| `env` | `List[EnvVar]` | Environment variables |
| `providers` | `Dict` | LLM provider configuration |
| `timeout` | `int` | Execution timeout in seconds |
| `retries` | `int` | Number of retry attempts |
| `parallelism` | `int` | Max parallel stage executions |

## Stage Spec Fields

| Field | Type | Description |
|-------|------|-------------|
| `id` | `str` | Stage identifier (required) |
| `componentType` | `str` | Component type (required) |
| `name` | `str` | Display name |
| `dependsOn` | `List[str]` | Stage dependencies |
| `config` | `Dict` | Stage configuration |
| `inputMapping` | `Dict` | Input field mapping |

## Kubernetes Client

### FlowMasonK8sClient

```python
from flowmason_core.kubernetes import FlowMasonK8sClient

# Initialize client (uses default kubeconfig)
client = FlowMasonK8sClient()

# Or with explicit config
client = FlowMasonK8sClient(
    kubeconfig_path="/path/to/kubeconfig",
    context="my-cluster"
)

# Create pipeline
await client.create_pipeline(pipeline)

# Get pipeline
pipeline = await client.get_pipeline("data-processor", namespace="production")

# List pipelines
pipelines = await client.list_pipelines(namespace="production")

# Update pipeline
await client.update_pipeline(pipeline)

# Delete pipeline
await client.delete_pipeline("data-processor", namespace="production")

# Trigger run
run = await client.create_run("data-processor", inputs={"date": "2025-12-14"})

# Get run status
status = await client.get_run_status(run.metadata["name"])
```

## Environment Variables

Inject secrets and configuration using Kubernetes secrets:

```yaml
spec:
  env:
    - name: ANTHROPIC_API_KEY
      valueFrom:
        secretKeyRef:
          name: llm-secrets
          key: anthropic-key
    - name: DATABASE_URL
      valueFrom:
        configMapKeyRef:
          name: app-config
          key: database-url
```

## Resource Management

Control resource allocation for pipeline executions:

```yaml
spec:
  resources:
    requests:
      memory: "256Mi"
      cpu: "100m"
    limits:
      memory: "1Gi"
      cpu: "1000m"
```

## Scheduling

### Cron Schedule

```yaml
spec:
  schedule: "0 */6 * * *"  # Every 6 hours
```

### Event Triggers

```yaml
spec:
  triggers:
    webhook:
      enabled: true
      path: /webhooks/data-processor
    pubsub:
      topic: pipeline-triggers
      subscription: data-processor-sub
```

## Installation

### Install CRDs

```bash
kubectl apply -f https://flowmason.io/k8s/crds/pipeline.yaml
kubectl apply -f https://flowmason.io/k8s/crds/pipelinerun.yaml
```

### Deploy Operator

```bash
# Using Helm
helm repo add flowmason https://charts.flowmason.io
helm install flowmason-operator flowmason/operator

# Or using kubectl
kubectl apply -f https://flowmason.io/k8s/operator.yaml
```

## CLI Commands

```bash
# Deploy pipeline to Kubernetes
fm k8s deploy pipeline.json --namespace production

# List pipelines
fm k8s list --namespace production

# Get pipeline status
fm k8s status data-processor --namespace production

# Trigger run
fm k8s run data-processor --namespace production --input date=2025-12-14

# View logs
fm k8s logs data-processor-run-001 --namespace production
```

## Monitoring

### Prometheus Metrics

The operator exposes metrics at `/metrics`:

- `flowmason_pipeline_runs_total`
- `flowmason_pipeline_run_duration_seconds`
- `flowmason_pipeline_run_errors_total`
- `flowmason_stage_duration_seconds`

### Example ServiceMonitor

```yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: flowmason-operator
spec:
  selector:
    matchLabels:
      app: flowmason-operator
  endpoints:
    - port: metrics
```

## Best Practices

1. **Use Namespaces**: Organize pipelines by environment or team
2. **Set Resource Limits**: Always set resource limits for production
3. **Use Secrets**: Store API keys in Kubernetes secrets
4. **Monitor Runs**: Set up alerting for failed runs
5. **Version Pipelines**: Use labels for version tracking


---

## 09-debugging-testing/debugging/visual-debugging.md

# Visual Debugging (Animated Execution)

FlowMason provides animated visualization of pipeline execution, allowing you to watch data flow through stages in real-time or replay recorded executions.

## Overview

```
┌─────────────────────────────────────────────────────────────────┐
│  Execution Visualization                          [▶ Play] [⏸] │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────┐  ═══▶  ┌─────────┐  ───▶  ┌─────────┐            │
│  │ fetch   │  data  │ process │        │ output  │            │
│  │ ✓ 1.2s  │  ════▶ │ ⟳ 45%   │        │ ○ wait  │            │
│  └─────────┘        └─────────┘        └─────────┘            │
│                          │                                      │
│                     ┌────┴────┐                                │
│                     │ Tokens: 234/1000                         │
│                     │ "Processing customer..."                  │
│                     └─────────┘                                │
│                                                                 │
│  Timeline: ═══════════════●═══════════════════════════════     │
│            0s            2.5s                           10s     │
└─────────────────────────────────────────────────────────────────┘
```

## Recording Executions

### Python API

```python
from flowmason_core.visualization import ExecutionRecorder

# Create recorder
recorder = ExecutionRecorder()

# Start recording
recorder.start_recording(
    run_id="run-123",
    pipeline_name="my-pipeline",
    stages=["fetch", "process", "output"]
)

# Record stage events (normally done automatically by executor)
recorder.record_stage_start("fetch")
recorder.record_stage_progress("fetch", 50)  # 50% complete
recorder.record_stage_complete("fetch", duration_ms=1200, output_preview='{"data": [...]}')

recorder.record_stage_start("process")
recorder.record_stage_progress("process", 25)
recorder.record_stage_progress("process", 50)
recorder.record_stage_progress("process", 75)
recorder.record_stage_complete("process", duration_ms=3500)

# Stop and get recording
recording = recorder.stop_recording()

print(f"Recorded {len(recording.frames)} frames")
print(f"Total duration: {recording.duration_ms}ms")
```

## Playback Controls

### ExecutionAnimator

```python
from flowmason_core.visualization import ExecutionAnimator

# Create animator from recording
animator = ExecutionAnimator(recording)

# Playback controls
animator.play()           # Start playback
animator.pause()          # Pause playback
animator.stop()           # Stop and reset
animator.seek(2500)       # Seek to 2.5 seconds
animator.seek_percent(50) # Seek to 50% of duration

# Speed control
animator.speed = 2.0      # 2x speed
animator.speed = 0.5      # Half speed

# Available speeds
print(animator.SPEED_OPTIONS)  # [0.5, 1.0, 2.0, 4.0]

# Navigation
animator.step_forward()       # Next frame
animator.step_backward()      # Previous frame
animator.skip_to_stage("process")  # Jump to stage
animator.skip_to_next_stage()
animator.skip_to_previous_stage()
```

### Callbacks

```python
# Set callbacks for UI updates
animator.set_frame_callback(lambda frame: update_ui(frame))
animator.set_position_callback(lambda pos: update_timeline(pos))

# Frame contains stage states
def update_ui(frame):
    for stage_id, stage_state in frame.stages.items():
        print(f"{stage_id}: {stage_state.status} ({stage_state.progress}%)")
```

## Export Formats

### RecordingExporter

```python
from flowmason_core.visualization import RecordingExporter
from flowmason_core.visualization.exporter import ExportFormat

exporter = RecordingExporter(recording)

# Export to JSON
json_data = exporter.export(ExportFormat.JSON)

# Export to HTML (interactive player)
html_page = exporter.export(ExportFormat.HTML)

# Export to Markdown (static report)
markdown = exporter.export(ExportFormat.MARKDOWN)

# Export to Mermaid diagram
mermaid = exporter.export(ExportFormat.MERMAID)

# Export to SVG sequence diagram
svg = exporter.export(ExportFormat.SVG_SEQUENCE)

# Save to file
exporter.export(ExportFormat.HTML, output_path=Path("execution.html"))
```

### Export Format Details

| Format | Description | Use Case |
|--------|-------------|----------|
| `JSON` | Raw recording data | API responses, storage |
| `HTML` | Interactive player | Sharing, documentation |
| `MARKDOWN` | Text report | README files, tickets |
| `MERMAID` | Mermaid.js diagram | Documentation |
| `SVG_SEQUENCE` | SVG sequence diagram | Presentations |

## Frame Types

```python
from flowmason_core.visualization import FrameType

# Available frame types
FrameType.STAGE_START      # Stage began execution
FrameType.STAGE_PROGRESS   # Progress update (0-100)
FrameType.STAGE_COMPLETE   # Stage finished successfully
FrameType.STAGE_ERROR      # Stage failed with error
FrameType.DATA_FLOW        # Data passed between stages
FrameType.TOKEN_STREAM     # LLM token streaming update
```

## VSCode Integration

### Opening Visual Debugger

1. Run a pipeline with debugging enabled
2. Click "Open Visual Debugger" in the debug toolbar
3. Or use Command Palette: `FlowMason: Open Visual Debugger`

### Features

- **Real-time Animation**: Watch execution as it happens
- **Timeline Scrubbing**: Drag to any point in time
- **Stage Details**: Click stages to see inputs/outputs
- **Token Streaming**: Watch LLM responses generate
- **Data Flow Arrows**: Animated data flow between stages

### Keyboard Shortcuts

| Key | Action |
|-----|--------|
| `Space` | Play/Pause |
| `←` | Step backward |
| `→` | Step forward |
| `[` | Previous stage |
| `]` | Next stage |
| `1-4` | Set speed (1x, 2x, 3x, 4x) |

## CLI Commands

```bash
# Record execution to file
fm run pipeline.json --record execution.json

# Play back recording
fm playback execution.json

# Export recording
fm export-recording execution.json --format html --output report.html
```

## Best Practices

1. **Record Important Runs**: Enable recording for debugging sessions
2. **Use Speed Controls**: Speed up long executions, slow down complex parts
3. **Export for Documentation**: Export HTML for sharing with team
4. **Monitor Token Usage**: Watch token streaming for LLM optimization

