DEV Community

Cover image for Mind's Eye Platform Official Technical Documentation
PEACEBINFLOW
PEACEBINFLOW

Posted on

Mind's Eye Platform Official Technical Documentation

Mind's Eye Platform — Official Technical Documentation

Version: 1.0.0 | Last Updated: December 6, 2025 | Status: MVP Active

An internal operating system for agents, ledgers, workflows, automation, cognitive layers, and orchestration


PROMPT 1 — System Overview (Engine Level, High Altitude)

Executive Summary

The Mind's Eye Platform is a cognitive automation operating system that treats workflows, data streams, and agent behaviors as first-class objects in a unified execution environment. Unlike traditional automation tools that connect APIs through linear pipelines, Mind's Eye implements a dual-engine architecture:

  1. MORCO (Mind's Eye Workflow Orchestration System) — The deterministic workflow execution runtime
  2. Hunting Engine — The probabilistic event detection and annotation system

Together, these engines form an Internal OS where Gmail serves as the canonical ledger, Google Workspace acts as the filesystem, and WebDocket provides the task management layer.

System Purpose

Mind's Eye exists to solve a fundamental problem in enterprise automation: the gap between structured workflows and unstructured reality.

Traditional automation tools assume:

  • Clean, structured inputs
  • Predictable execution paths
  • Single-source triggers
  • Stateless operations

But real business processes involve:

  • Messy, multi-source data streams
  • Context-dependent branching
  • Long-running state across systems
  • Human-in-the-loop decision points
  • Post-hoc analysis and learning

Mind's Eye bridges this gap by providing:

  • MORCO for structured, repeatable workflows
  • Hunting Engine for pattern detection in unstructured streams
  • Gmail Ledger for canonical state across all operations
  • Cognitive Layers for progressively intelligent automation

Core Vision and Principles

Vision Statement

"Build an automation OS where every event, decision, and state change is logged, traceable, queryable, and learnable — enabling systems that evolve from rule-based automation to cognitive orchestration."

Foundational Principles

1. Ledger-First Architecture

  • Gmail is the source of truth for all workflow state
  • Every significant event generates a ledger entry
  • Machine-readable logs enable future analytics and learning
  • Audit trails are automatic, not bolted-on

2. Explicit State Management

  • Correlation IDs track complete workflow runs across services
  • Run state is persisted at every step
  • No hidden state or implicit context
  • Replay and debugging are first-class operations

3. Binary Logic for Branching

  • All conditional execution uses explicit boolean expressions
  • Steps declare: should_run_expr, on_success, on_failure
  • No magic — every path is documented
  • Deterministic execution, even with external dependencies

4. Service Orchestration, Not Integration

  • Connectors abstract service APIs behind consistent interfaces
  • Workflows compose services, not endpoints
  • Separation of concerns: orchestration logic vs. service implementation

5. Progressive Cognitive Enhancement

  • Start with structured workflows (L1-L2)
  • Add pattern detection (L3-L4)
  • Evolve toward predictive automation (L5)
  • The system learns from its own ledger

The Hunting Engine: Why It Exists

The Problem

MORCO handles known workflows — processes you can define upfront with clear triggers, steps, and outcomes. But what about:

  • Detecting anomalies in invoice patterns?
  • Finding related dockets across disconnected systems?
  • Discovering implicit workflows that humans perform manually?
  • Learning from past runs to predict future failures?

These require pattern recognition, not just execution.

The Solution: Hunting Engine

The Hunting Engine is a probabilistic event stream processor that:

  1. Monitors Sources: Gmail, WebDocket, Forms, Docs, external APIs
  2. Detects Patterns: Uses hunts (detection rules) to find interesting events
  3. Creates Annotations: Tags events with metadata, relationships, and insights
  4. Writes to Ledger: Feeds discoveries back into Gmail for MORCO consumption

Example Use Cases:

  • Hunt: "Find all invoices submitted by the same vendor within 24 hours"
  • Hunt: "Detect when a docket status changes but no action was logged"
  • Hunt: "Identify form submissions with suspicious email patterns"
  • Hunt: "Discover implicit dependencies between workflows by correlation ID analysis"

Architecture Philosophy

MORCO = Deterministic ("Do this when X happens")
Hunting Engine = Probabilistic ("Tell me when you see X pattern")

Together = Reactive + Proactive Automation
Enter fullscreen mode Exit fullscreen mode

The Hunting Engine creates a cognitive feedback loop:

  1. MORCO executes workflows → generates ledger events
  2. Hunting Engine analyzes ledger → detects patterns
  3. Annotations feed back into MORCO → trigger new workflows
  4. System becomes progressively smarter

The Workflow OS: MORCO and the Ledger System

MORCO as Runtime

MORCO is the execution kernel of Mind's Eye. It:

  • Loads workflow definitions (JSON specifications)
  • Receives triggers (Forms, WebDocket, Chatbot, Cron)
  • Executes steps sequentially with conditional branching
  • Manages state across service boundaries
  • Writes execution traces to the Gmail ledger

MORCO is to Mind's Eye what the Linux kernel is to an OS — it schedules work, manages resources, and provides the execution environment.

Gmail as the Canonical Ledger

In traditional systems:

  • Logs are ephemeral (files, stdout)
  • State is scattered (databases, caches, APIs)
  • Audit trails are reconstructed

In Mind's Eye:

  • Gmail IS the state
  • Every workflow event = one ledger email
  • Structured subjects enable instant querying: [LEDGER] workflow=invoice-intake event=step_completed cid=uuid
  • Email labels create automatic categorization
  • Native search, filters, and retention policies

Why Gmail?

  1. Durability: Google's infrastructure, built-in redundancy
  2. Queryability: Powerful search with filters, labels, time ranges
  3. Accessibility: Any service can read/write via API
  4. Familiarity: Everyone knows email
  5. Machine + Human Readable: Structured data in familiar format
  6. Free: Up to 15GB per account

The Ledger System as Filesystem

Think of Gmail labels as directories:

ledger/
  workflows/
    invoice-intake/
      run-uuid-001/
      run-uuid-002/
    meeting-notes/
      run-uuid-003/
  errors/
  validations/
  analytics/
Enter fullscreen mode Exit fullscreen mode

Each email is an immutable log entry with:

  • Subject = metadata (workflow, event, correlation ID)
  • Body = full state snapshot (trigger, inputs, outputs, errors)
  • Timestamp = built-in
  • Thread = related events automatically grouped

Cognitive Layers (L1-L5)

Mind's Eye is designed for progressive enhancement — start simple, add intelligence over time.

Layer 1: Direct Execution (Current MVP)

  • Trigger → Workflow → Steps → Services → Ledger
  • No conditionals, no branching
  • Example: Form submit → Create doc → Send email

Layer 2: Conditional Logic (Current MVP)

  • Binary logic: should_run_expr evaluates to 1 or 0
  • Branching: on_success, on_failure
  • Example: Validate invoice → if valid, create docket; if invalid, notify submitter

Layer 3: Pattern Detection (Hunting Engine MVP)

  • Hunts monitor event streams
  • Annotations tag interesting patterns
  • Example: Detect duplicate invoices, trigger validation workflow

Layer 4: Context-Aware Orchestration (Roadmap)

  • Workflows access historical ledger data
  • Decisions based on past runs
  • Example: Prioritize dockets based on previous similar cases

Layer 5: Predictive Automation (Future)

  • ML models trained on ledger data
  • Proactive workflow triggers
  • Example: Predict invoice disputes before they occur, pre-emptively assign reviewers

Current Status: L1-L3 implemented in MVP

Why This Architecture Is Different

Standard Automation Tools

Zapier / IFTTT Model:

  • Simple trigger-action pairs
  • Limited branching
  • No state management
  • Logs are ephemeral
  • No learning or pattern detection

n8n / Integromat Model:

  • Visual workflow builder
  • More complex logic
  • Some state management
  • Logs in proprietary format
  • Limited cross-workflow analysis

Google Apps Script Model:

  • Code-based automation
  • Full programmatic control
  • Manual state management
  • Logs are console output
  • No unified execution model

Xano / Backend-as-a-Service Model:

  • Database-centric
  • API generation
  • Custom business logic
  • Logs are application-level
  • No workflow abstraction

Mind's Eye Differences

Feature Traditional Tools Mind's Eye
State Management Implicit, scattered Explicit, ledger-first
Logs Ephemeral, proprietary Durable, Gmail-based
Traceability Correlation ID if lucky Correlation ID mandatory
Branching Visual/nested Binary logic, explicit
Pattern Detection None Hunting Engine
Learning None Cognitive layers
Audit Trail Paid add-on Built-in
Multi-Workflow Separate Unified via ledger
Replay Impossible Ledger + correlation ID
Cost Per execution Gmail + compute

Platform Comparison

vs. Zapier

Zapier Strengths:

  • 5000+ integrations
  • No code required
  • Fast to set up

Zapier Limitations:

  • Limited to 1 trigger per Zap
  • Complex branching requires premium tier
  • No unified state across Zaps
  • No learning or pattern detection
  • Expensive at scale

Mind's Eye Advantage:

  • Unlimited complexity in workflows
  • Unified state via ledger
  • Cross-workflow analysis via Hunting Engine
  • Own your data and execution
  • Gmail ledger provides free audit trail

vs. n8n

n8n Strengths:

  • Self-hosted option
  • Visual workflow designer
  • More complex logic than Zapier

n8n Limitations:

  • Still workflow-centric, not OS-centric
  • Logs are in proprietary format
  • No pattern detection layer
  • State management is implicit

Mind's Eye Advantage:

  • Ledger-first architecture
  • Dual engine (MORCO + Hunting)
  • Gmail as queryable state

  • Designed for cognitive enhancement

vs. Google Apps Script

Apps Script Strengths:

  • Full programmatic control
  • Native Google Workspace integration
  • Free for Google Workspace users

Apps Script Limitations:

  • No workflow abstraction
  • Manual state management
  • Code is scattered across projects
  • No unified execution model
  • Limited to 6 min execution time

Mind's Eye Advantage:

  • Workflow JSON = declarative configuration
  • Automatic state management
  • Unified orchestration layer
  • Ledger provides cross-script visibility
  • Can call Apps Script as connector

vs. Xano

Xano Strengths:

  • Full backend stack
  • Database included
  • API generation

Xano Limitations:

  • Database-centric, not workflow-centric
  • No workflow execution model
  • Manual orchestration logic
  • No pattern detection

Mind's Eye Advantage:

  • Workflow-first design
  • Gmail ledger = distributed database
  • Built-in orchestration runtime
  • Hunting Engine for insights

System Diagram: The Full Stack

┌─────────────────────────────────────────────────────────────┐
│                     MIND'S EYE PLATFORM                     │
│                    (Internal OS Layer)                       │
└─────────────────────────────────────────────────────────────┘

┌──────────────────────┐         ┌──────────────────────────┐
│   MORCO ENGINE       │         │   HUNTING ENGINE         │
│  (Deterministic)     │◄────────┤   (Probabilistic)        │
│                      │         │                          │
│ • Workflow Executor  │         │ • Stream Processor       │
│ • Binary Logic       │         │ • Pattern Matcher        │
│ • State Manager      │         │ • Annotation Engine      │
│ • Connector Layer    │         │ • Relationship Detector  │
└──────────┬───────────┘         └────────┬─────────────────┘
           │                              │
           └──────────┬───────────────────┘
                      │
                      ▼
           ┌──────────────────────┐
           │   GMAIL LEDGER       │
           │  (Canonical State)   │
           │                      │
           │ • Structured Logs    │
           │ • Correlation IDs    │
           │ • Queryable History  │
           │ • Auto-Categorized   │
           └──────────┬───────────┘
                      │
         ─────────────┴─────────────
        │                           │
        ▼                           ▼
┌───────────────┐           ┌──────────────┐
│   TRIGGERS    │           │  CONNECTORS  │
│               │           │              │
│ • Forms       │           │ • Gmail      │
│ • WebDocket   │           │ • Docs       │
│ • Chatbot     │           │ • Forms      │
│ • Cron        │           │ • WebDocket  │
│ • Ledger      │           │ • External   │
└───────────────┘           └──────────────┘
Enter fullscreen mode Exit fullscreen mode

Analogies for Understanding Mind's Eye

Computer Science Analogies

MORCO = Operating System Kernel

  • Schedules workflow execution
  • Manages resources (API calls, rate limits)
  • Provides isolation (correlation IDs)
  • Handles errors (try/catch semantics)

Hunting Engine = Intrusion Detection System (IDS)

  • Monitors network traffic (event streams)
  • Detects patterns (hunts)
  • Flags anomalies (annotations)
  • Writes to SIEM (ledger)

Gmail Ledger = Write-Ahead Log (WAL)

  • Immutable append-only log
  • Durable before application state changes
  • Enables replay and recovery
  • Source of truth for state

Workflows = Programs

  • Declarative specifications
  • Executed by runtime
  • Have inputs, outputs, and side effects

Connectors = System Calls

  • Abstract hardware (external APIs)
  • Provide consistent interface
  • Handle errors and retries

Business Process Analogies

MORCO = Standard Operating Procedure (SOP)

  • Documented, repeatable process
  • Clear steps and decision points
  • Everyone follows the same procedure

Hunting Engine = Quality Assurance (QA)

  • Reviews completed work
  • Finds patterns and issues
  • Reports back to improve processes

Gmail Ledger = Audit Log Book

  • Every transaction recorded
  • Timestamped and signed
  • Can be reviewed later
  • Required for compliance

Correlation ID = Case Number

  • Tracks a single case across departments
  • All documents reference the same ID
  • Easy to find all related work

Systems Thinking: Feedback Loops

Mind's Eye implements multiple feedback loops for continuous improvement:

Loop 1: Execution → Logging → Analysis

Workflow Runs → Ledger Events → Manual Review → Workflow Updates

Loop 2: Pattern Detection → Automation

Loop 2: Pattern Detection → Automation

Hunting Engine Detects Pattern → Create New Workflow → More Data → Better Patterns
Enter fullscreen mode Exit fullscreen mode

Loop 3: Failure Learning

Workflow Fails → Error Logged → Hunt Detects Similar Failures → Proactive Prevention
Enter fullscreen mode Exit fullscreen mode

Loop 4: Cross-Workflow Optimization

Multiple Workflows → Ledger Analysis → Find Redundancy → Consolidate → More Efficient
Enter fullscreen mode Exit fullscreen mode

These loops enable emergent intelligence — the system becomes smarter not through explicit programming, but through analysis of its own behavior.


PROMPT 2 — Mind's Eye Engine Architecture (The Core Block)

Internal Object Model

The Mind's Eye platform operates on six core object types that form the foundation of both MORCO and the Hunting Engine.

Object Type 1: Sources

Definition: External systems that generate events or can be queried for data.

Attributes:

  • source_id: Unique identifier (e.g., gmail-primary, webdocket-prod)
  • source_type: Service category (gmail, google_forms, webdocket, google_docs, chatbot)
  • connection_config: Authentication and endpoint configuration
  • poll_interval: For polling sources (e.g., every 5 minutes)
  • webhook_url: For push sources
  • is_active: Whether the source is currently monitored

Examples:

{
  "source_id": "gmail-primary",
  "source_type": "gmail",
  "connection_config": {
    "account": "[ledger@company.com](mailto:ledger@company.com)",
    "labels": ["MORCO/Workflows", "MORCO/Triggers"]
  },
  "poll_interval": null,
  "webhook_url": null,
  "is_active": true
}
Enter fullscreen mode Exit fullscreen mode

Object Type 2: Streams

Definition: Continuous flows of events from sources, with optional filtering and transformation.

Attributes:

  • stream_id: Unique identifier
  • source_id: Parent source
  • filter_expr: Optional filter (e.g., "only emails with subject containing [TRIGGER]")
  • transform_rules: Optional transformation logic
  • buffer_size: How many events to hold in memory
  • backpressure_strategy: What to do when buffer is full

Examples:

{
  "stream_id": "invoice-form-submissions",
  "source_id": "google-forms-finance",
  "filter_expr": "form_id == 'finance_invoice_intake'",
  "transform_rules": [
    {"field": "amount", "type": "parse_number"},
    {"field": "due_date", "type": "parse_date"}
  ],
  "buffer_size": 100,
  "backpressure_strategy": "drop_oldest"
}
Enter fullscreen mode Exit fullscreen mode

Object Type 3: Events

Definition: Individual occurrences in a stream, representing something that happened.

Attributes:

  • event_id: Unique identifier (UUID)
  • stream_id: Parent stream
  • event_type: Classification (e.g., form_submit, docket_created, email_received)
  • timestamp: When the event occurred
  • payload: The event data (JSON)
  • metadata: Additional context (source IP, user agent, etc.)
  • correlation_id: Links this event to related events

Examples:

{
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "stream_id": "invoice-form-submissions",
  "event_type": "form_submit",
  "timestamp": "2025-12-06T07:30:00Z",
  "payload": {
    "vendor_name": "Acme Corp",
    "invoice_number": "INV-2025-001",
    "amount": 5000.00
  },
  "metadata": {
    "form_id": "finance_invoice_intake",
    "submitter_email": "[vendor@acme.com](mailto:vendor@acme.com)"
  },
  "correlation_id": null
}
Enter fullscreen mode Exit fullscreen mode

Object Type 4: Hunts

Definition: Pattern detection rules that analyze event streams to find interesting occurrences.

Attributes:

  • hunt_id: Unique identifier
  • hunt_name: Human-readable name
  • description: What pattern this hunt detects
  • stream_ids: Which streams to monitor
  • detection_logic: The pattern matching rule
  • window_size: Time window for pattern detection (e.g., "24 hours")
  • threshold: How many matches constitute a detection
  • action: What to do when pattern is detected

Examples:

{
  "hunt_id": "duplicate-invoice-detector",
  "hunt_name": "Duplicate Invoice Detection",
  "description": "Detects when the same vendor submits invoices with identical invoice numbers within 24 hours",
  "stream_ids": ["invoice-form-submissions"],
  "detection_logic": {
    "group_by": ["payload.vendor_name", "payload.invoice_number"],
    "count": ">= 2",
    "within": "24h"
  },
  "window_size": "24h",
  "threshold": 2,
  "action": {
    "type": "create_annotation",
    "trigger_workflow": "duplicate-invoice-review"
  }
}
Enter fullscreen mode Exit fullscreen mode

Object Type 5: Hunt Runs

Definition: Executions of hunts, tracking what was detected and when.

Attributes:

  • hunt_run_id: Unique identifier
  • hunt_id: Parent hunt
  • start_time: When the hunt run began
  • end_time: When the hunt run completed
  • events_analyzed: Count of events processed
  • matches_found: Count of pattern matches
  • annotations_created: Count of annotations generated
  • status: running, completed, failed
  • error: If failed, the error details

Examples:

{
  "hunt_run_id": "hr-20251206-073000",
  "hunt_id": "duplicate-invoice-detector",
  "start_time": "2025-12-06T07:30:00Z",
  "end_time": "2025-12-06T07:30:05Z",
  "events_analyzed": 47,
  "matches_found": 1,
  "annotations_created": 2,
  "status": "completed",
  "error": null
}
Enter fullscreen mode Exit fullscreen mode

Object Type 6: Annotations

Definition: Metadata tags applied to events by hunts, enriching them with insights.

Attributes:

  • annotation_id: Unique identifier
  • event_id: Which event is being annotated
  • hunt_run_id: Which hunt run created this annotation
  • annotation_type: Classification (e.g., duplicate, anomaly, relationship)
  • confidence: 0.0 to 1.0, how confident the detection is
  • details: Structured data about the annotation
  • related_events: Links to other relevant events
  • timestamp: When the annotation was created

Examples:

{
  "annotation_id": "ann-001",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "hunt_run_id": "hr-20251206-073000",
  "annotation_type": "duplicate",
  "confidence": 0.95,
  "details": {
    "reason": "Same vendor, same invoice number",
    "duplicate_of": "event-550e8400-e29b-41d4-a716-446655440001",
    "time_delta": "3 hours"
  },
  "related_events": ["550e8400-e29b-41d4-a716-446655440001"],
  "timestamp": "2025-12-06T07:30:05Z"
}
Enter fullscreen mode Exit fullscreen mode

Event Flow Through the Engine

The Complete Journey

┌─────────────┐
│   SOURCE    │  (Gmail, Forms, WebDocket, etc.)
└──────┬──────┘
       │ New event occurs
       ▼
┌─────────────┐
│   STREAM    │  Filter & Transform
└──────┬──────┘
       │ Event passes filter
       ▼
┌─────────────┐
│    EVENT    │  Created with UUID, stored
└──────┬──────┘
       │
       ├──────────────────────────┐
       │                          │
       ▼                          ▼
┌─────────────┐          ┌───────────────┐
│  MORCO      │          │ HUNTING       │
│  TRIGGER    │          │ ENGINE        │
│  MATCHER    │          │ ANALYZER      │
└──────┬──────┘          └───────┬───────┘
       │                         │
       │ Match found             │ Pattern detected
       ▼                         ▼
┌─────────────┐          ┌───────────────┐
│ WORKFLOW    │          │  HUNT RUN     │
│ EXECUTION   │          │               │
└──────┬──────┘          └───────┬───────┘
       │                         │
       │ Steps run               │ Annotations created
       ▼                         ▼
┌─────────────┐          ┌───────────────┐
│ CONNECTORS  │          │ ANNOTATIONS   │
└──────┬──────┘          └───────┬───────┘
       │                         │
       │ Actions executed        │
       ▼                         ▼
┌──────────────────────────────────┐
│       GMAIL LEDGER               │
│  • workflow_triggered            │
│  • step_completed                │
│  • pattern_detected              │
│  • annotation_created            │
└──────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Step 1: Event Ingestion

  • Source generates event (form submit, webhook, etc.)
  • Stream receives and validates event
  • Event object created with UUID

Step 2: Trigger Matching

for each workflow in registry:
  if workflow.trigger.matches(event):
    create_run_context(workflow, event)
    queue_for_execution(run_context)
Enter fullscreen mode Exit fullscreen mode

Step 3: Run Context Creation

{
  "run_id": "run-550e8400",
  "correlation_id": "550e8400-e29b-41d4-a716-446655440000",
  "workflow_name": "invoice-intake-and-validation",
  "trigger_event": {...},
  "step_results": {},
  "current_step": null,
  "status": "queued",
  "created_at": "2025-12-06T07:30:00Z"
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Orchestrator Picks Up Run

  • Dequeue from execution queue
  • Set status = "running"
  • Write initial ledger email: event=workflow_triggered

Step 5: Step-by-Step Execution

For each step in workflow.steps:
  ↓
  Evaluate binary_logic.should_run_expr
  ↓
  If evaluates to 0 → Skip step, continue
  If evaluates to 1 → Execute step
  ↓
  Resolve template variables in step.inputs
  ↓
  Call connector: connector.execute(step.service, step.action, resolved_inputs)
  ↓
  Store result in run_state.step_results[[step.id](http://step.id)]
  ↓
  If step.binary_logic.log_to_ledger == true:
    Write ledger email: event=step_completed
  ↓
  If connector returned error:
    Handle via step.binary_logic.on_failure
  Else:
    Continue via step.binary_logic.on_success
Enter fullscreen mode Exit fullscreen mode

Step 6: Completion

  • Set status = "completed" or "failed"
  • Write final ledger email: event=workflow_completed or event=workflow_failed
  • Update run record in database (if using internal DB)

Detailed Flow: Hunting Engine Path

Step 1: Continuous Stream Analysis

for each hunt in active_hunts:
  events = get_events_in_window([hunt.stream](http://hunt.stream)_ids, hunt.window_size)
  matches = apply_detection_logic(hunt.detection_logic, events)

  if matches.length >= hunt.threshold:
    create_hunt_run(hunt, matches)
Enter fullscreen mode Exit fullscreen mode

Step 2: Hunt Run Execution

  • Create hunt run record
  • Apply annotation logic to matched events
  • Generate annotations with confidence scores

Step 3: Annotation Creation

for each match in matches:
  annotation = {
    event_id: match.event_id,
    type: hunt.annotation_type,
    confidence: calculate_confidence(match),
    details: extract_details(match),
    related_events: find_related(match)
  }

  store_annotation(annotation)

  if hunt.action.trigger_workflow:
    create_trigger_event_for_morco(annotation)
Enter fullscreen mode Exit fullscreen mode

Step 4: Feedback to MORCO

  • If hunt specifies trigger_workflow
  • Create synthetic event with entry_point = "hunting_engine"
  • Event payload includes annotation details
  • MORCO picks up and executes specified workflow

Step 5: Ledger Integration

  • Write ledger email: event=pattern_detected
  • Include hunt details, matched events, annotations
  • This makes pattern detections queryable like workflow runs

Run State Management

The Run State Object

Every workflow execution maintains a run state object that persists throughout the entire workflow.

Structure:

interface RunState {
  // Identity
  run_id: string;              // Unique run identifier
  correlation_id: string;      // Links related runs
  workflow_name: string;       // Which workflow is running

  // Execution context
  trigger: {
    event_id: string;
    event_type: string;
    payload: any;
    timestamp: string;
  };

  // Step results (the key to data flow)
  step_results: Record<string, {
    outputs: any;
    status: 'success' | 'failed';
    error?: string;
    started_at: string;
    completed_at: string;
  }>;

  // Current execution state
  current_step: string | null;
  status: 'queued' | 'running' | 'completed' | 'failed';

  // Timestamps
  created_at: string;
  started_at?: string;
  completed_at?: string;

  // Ledger tracking
  ledger_emails_sent: string[];  // Message IDs

  // Error handling
  error?: {
    step_id: string;
    message: string;
    stack?: string;
  };
}
Enter fullscreen mode Exit fullscreen mode

State Persistence Strategy

Option 1: In-Memory Only (Simple, good for MVP)

  • Run state lives in memory during execution
  • Only persisted via ledger emails
  • If orchestrator crashes, can reconstruct from ledger

Option 2: Database Backed (Production)

  • Run state written to DB after each step
  • Enables:
    • Active run monitoring
    • Mid-workflow recovery
    • Real-time dashboards
    • Run history queries

Option 3: Hybrid (Recommended)

  • In-memory during execution (fast)
  • Write to DB at key checkpoints (durable)
  • Always write to ledger (audit trail)

Correlation IDs: The Tracing System

Purpose

Correlation IDs solve the distributed tracing problem: when a workflow spans multiple services, how do you track all related actions?

How They Work

1. ID Generation

  • When a workflow run is created, generate a UUID
  • This becomes the correlation_id for the entire run
  • All subsequent actions inherit this ID

2. ID Propagation

  • Every connector call receives the correlation ID
  • Connectors include it in:
    • API calls (as header: X-Correlation-ID)
    • Ledger emails (in subject and body)
    • External system metadata (if supported)

3. Cross-Service Tracing

Form Submit
  ↓ correlation_id: abc-123
Workflow Triggered
  ↓ correlation_id: abc-123
Step 1: Create Doc → Doc metadata includes abc-123
  ↓ correlation_id: abc-123
Step 2: Create Docket → Docket custom field = abc-123
  ↓ correlation_id: abc-123
Step 3: Send Email → Email subject includes abc-123
  ↓ correlation_id: abc-123
Ledger Email → Subject: [LEDGER] cid=abc-123
Enter fullscreen mode Exit fullscreen mode

4. Ledger Query

Gmail search: "[LEDGER] cid=abc-123"
→ Returns all ledger emails for this workflow run
→ Complete audit trail, timestamped, with full state
Enter fullscreen mode Exit fullscreen mode

Cross-Workflow Correlation

Sometimes workflows trigger other workflows:

Invoice Intake (cid: abc-123)
  ↓ Creates docket
Docket Status Change (new cid: def-456)
  ↓ References original invoice
  ↓ metadata.parent_correlation_id = abc-123
Enter fullscreen mode Exit fullscreen mode

Hunting Engine can detect these relationships:

{
  "hunt_name": "Workflow Chain Detector",
  "detection_logic": {
    "find": "events where metadata contains parent_correlation_id",
    "create_annotation": {
      "type": "workflow_chain",
      "details": "Links workflows: abc-123 → def-456"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Ledger Email Integration

When Ledger Emails Fire

Each workflow defines which events trigger ledger emails:

{
"gmail_ledger": {
"enabled": true,
"ledger_recipient": "ledger@company.com",
"log_events": [
"workflow_triggered",
"step_completed",
"validation_failed",
"error"
]
}
}

Individual steps can override:

{
  "step": {
    "id": "step_3",
    "binary_logic": {
      "log_to_ledger": true  // Force log even if not in global list
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Ledger Email Format

Subject Template:

[LEDGER] workflow={workflow_name} event={event_type} cid={correlation_id}
Enter fullscreen mode Exit fullscreen mode

Body Template:

WORKFLOW: {workflow_name}
EVENT: {event_type}
CORRELATION_ID: {correlation_id}
RUN_ID: {run_id}
TIMESTAMP: {timestamp}

=== TRIGGER ===
SOURCE: {trigger.source}
TYPE: {trigger.event_type}
PAYLOAD:
{trigger.payload | json_pretty}

=== STEP ===
STEP_ID: {[step.id](http://step.id)}
SERVICE: {step.service}
ACTION: {step.action}

INPUTS:
{step.inputs | json_pretty}

OUTPUTS:
{step.outputs | json_pretty}

=== STATUS ===
STATUS: {status}
ERROR: {error | default: "none"}

=== METADATA ===
RUN_DURATION: {duration_ms}ms
STEPS_COMPLETED: {steps_completed} / {total_steps}
LEDGER_EMAILS_SENT: {ledger_count}
Enter fullscreen mode Exit fullscreen mode

Gmail Label Strategy

Automatic labeling for organization:

MORCO/Ledger (all ledger emails)
MORCO/Workflows/{name} (per workflow)
MORCO/Events/{type} (per event type)
MORCO/Status/Success (successful runs)
MORCO/Status/Failed (failed runs)
MORCO/Hunting (pattern detections)

Step Results Storage

The Step Results Map

Each step's outputs are stored in run_state.step_results[step_id]:

run_state.step_results = {
  "step_1": {
    "outputs": {
      "is_valid": true,
      "normalized_payload": {...}
    },
    "status": "success",
    "started_at": "2025-12-06T07:30:01Z",
    "completed_at": "2025-12-06T07:30:02Z"
  },
  "step_2": {
    "outputs": {
      "doc_id": "1abc123",
      "doc_url": "https://docs.google.com/..."
    },
    "status": "success",
    "started_at": "2025-12-06T07:30:02Z",
    "completed_at": "2025-12-06T07:30:04Z"
  }
}
Enter fullscreen mode Exit fullscreen mode

Template Resolution

Later steps can reference earlier step outputs using template syntax:

In Workflow JSON:

{
  "step_3": {
    "inputs": {
      "doc_url": "step_2.outputs.doc_url",
      "validation_result": "step_[1.outputs.is](http://1.outputs.is)_valid"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Resolution at Runtime:

function resolveTemplates(inputs: any, runState: RunState): any {
  const resolved = {};

  for (const [key, value] of Object.entries(inputs)) {
    if (typeof value === 'string' && value.startsWith('step_')) {
      // Parse reference: "step_2.outputs.doc_url"
      const [stepId, ...path] = value.split('.');
      resolved[key] = getNestedValue(runState.step_results, [stepId, ...path]);
    } else if (typeof value === 'string' && value.startsWith('trigger.')) {
      // Parse reference: "trigger.vendor_name"
      const path = value.substring(8); // Remove 'trigger.'
      resolved[key] = getNestedValue(runState.trigger.payload, path.split('.'));
    } else {
      resolved[key] = value;
    }
  }

  return resolved;
}
Enter fullscreen mode Exit fullscreen mode

Binary Logic and Branching

The Binary Logic Block

Every step includes a binary_logic configuration:

{
  "binary_logic": {
    "should_run_expr": "1",
    "on_success": "proceed to step_3",
    "on_failure": "log error and halt workflow",
    "log_to_ledger": true
  }
}
Enter fullscreen mode Exit fullscreen mode

Conditional Execution: should_run_expr

This expression evaluates to 1 (run) or 0 (skip).

Simple Examples:

"1"                           → Always run
"0"                           → Never run (disabled step)
"step_[1.outputs.is](http://1.outputs.is)_valid"    → Run if validation passed
Enter fullscreen mode Exit fullscreen mode

Complex Examples:

"step_1.outputs.amount > 5000"                          → Run for high-value invoices
"trigger.priority == 'urgent'"                          → Run only for urgent requests
"step_2.outputs.doc_id != null"                         → Run if doc was created
"step_[1.outputs.is](http://1.outputs.is)_valid && trigger.amount > 1000"     → Boolean AND
"trigger.status == 'completed' || trigger.status == 'approved'"  → Boolean OR
Enter fullscreen mode Exit fullscreen mode

Evaluation Engine:

function evaluateShouldRun(expr: string, runState: RunState): boolean {
  // Replace template variables
  const resolved = resolveTemplates({expr}, runState).expr;

  // If it's a simple "1" or "0"
  if (resolved === "1" || resolved === "0") {
    return resolved === "1";
  }

  // If it's a boolean value from a previous step
  if (typeof resolved === 'boolean') {
    return resolved;
  }

  // If it's a comparison expression, evaluate it
  // (In production, use a safe expression evaluator like expr-eval)
  return evalSafely(resolved);
}
Enter fullscreen mode Exit fullscreen mode

Branch Handling: on_success and on_failure

Supported Strategies:

  1. Continue to next step (default)

    {"on_success": "proceed to step_3"}
    
  2. Skip to specific step

    {"on_success": "jump to step_5"}
    
  3. Halt workflow

    {"on_failure": "halt workflow"}
    
  4. Log and continue

    {"on_failure": "log error and continue"}
    
  5. Trigger different workflow

    {"on_failure": "trigger workflow error-handler-workflow"}
    

Branching Example

{
  "steps": [
    {
      "id": "step_1",
      "service": "google_forms",
      "action": "validate_submission",
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed to step_2",
        "on_failure": "jump to step_error"
      }
    },
    {
      "id": "step_2",
      "service": "google_docs",
      "action": "create_doc",
      "binary_logic": {
        "should_run_expr": "step_[1.outputs.is](http://1.outputs.is)_valid",
        "on_success": "proceed to step_3"
      }
    },
    {
      "id": "step_3",
      "service": "gmail",
      "action": "send_email",
      "binary_logic": {
        "should_run_expr": "1"
      }
    },
    {
      "id": "step_error",
      "service": "gmail",
      "action": "send_email",
      "inputs": {
        "to": "[admin@company.com](mailto:admin@company.com)",
        "subject": "Validation Failed",
        "body": "step_1.outputs.error"
      },
      "binary_logic": {
        "should_run_expr": "!step_[1.outputs.is](http://1.outputs.is)_valid",
        "on_success": "halt workflow"
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Execution Path 1 (Happy Path):

step_1 (validate) → success → step_2 (create doc) → step_3 (send email) → done
Enter fullscreen mode Exit fullscreen mode

Execution Path 2 (Validation Failed):

step_1 (validate) → failure → step_error (notify admin) → halt
Enter fullscreen mode Exit fullscreen mode

Architecture Diagram: Internal Flow

┌─────────────────────────────────────────────────────────────────┐
│                    EXTERNAL TRIGGER                             │
│  (Form Submit, WebDocket Webhook, Chatbot Message, Cron Job)   │
└────────────────────────────┬────────────────────────────────────┘
                             │
                             ▼
                  ┌────────────────────┐
                  │  TRIGGER INGESTION │
                  │  • Normalize event │
                  │  • Generate UUID   │
                  │  • Match workflow  │
                  └─────────┬──────────┘
                            │
                            ▼
                  ┌────────────────────┐
                  │ CREATE RUN CONTEXT │
                  │  • correlation_id  │
                  │  • run_state       │
                  │  • step_results {} │
                  └─────────┬──────────┘
                            │
                            ▼
            ┌───────────────────────────────────┐
            │      WORKFLOW ORCHESTRATOR        │
            │  (The Execution Loop)             │
            └───────────────┬───────────────────┘
                            │
                  ┌─────────▼─────────┐
                  │  FOR EACH STEP    │
                  └─────────┬─────────┘
                            │
           ┌────────────────┼────────────────┐
           │                │                │
           ▼                ▼                ▼
    ┌──────────┐    ┌─────────────┐   ┌──────────┐
    │ Evaluate │    │   Resolve   │   │ Execute  │
    │should_run│ →  │  Templates  │ → │Connector │
    └──────────┘    └─────────────┘   └────┬─────┘
                                            │
                                            ▼
                                   ┌─────────────────┐
                                   │ CONNECTOR LAYER │
                                   │ • Gmail         │
                                   │ • Docs          │
                                   │ • Forms         │
                                   │ • WebDocket     │
                                   └────────┬────────┘
                                            │
                ┌───────────────────────────┼────────────────────┐
                │                           │                    │
                ▼                           ▼                    ▼
        ┌──────────────┐           ┌───────────────┐   ┌────────────────┐
        │ Store Result │           │  Log to       │   │  Handle Error  │
        │ in step_     │           │  Ledger       │   │  (on_failure)  │
        │ results[id]  │           │  (if enabled) │   │                │
        └──────┬───────┘           └───────────────┘   └────────────────┘
               │
               ▼
        ┌─────────────┐
        │  on_success │
        │  on_failure │
        │  handlers   │
        └──────┬──────┘
               │
               ▼
        ┌─────────────┐
        │  Next Step  │ ─── Loop continues
        └─────────────┘
               │
               ▼
        ┌─────────────┐
        │  Workflow   │
        │  Complete   │
        └──────┬──────┘
               │
               ▼
        ┌────────────────────┐
        │  GMAIL LEDGER      │
        │  • Complete trace  │
        │  • All step data   │
        │  • Correlation ID  │
        │  • Queryable       │
        └────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Component Deep Dive

1. Trigger Ingestion Layer

Responsibilities:

  • Accept events from external sources
  • Normalize to standard format
  • Route to appropriate workflow(s)

Implementation Pattern:

class TriggerIngestion {
  async handleWebhook(req: Request): Promise<void> {
    // Extract event data
    const rawEvent = req.body;

    // Normalize
    const event: Event = {
      event_id: generateUUID(),
      event_type: detectEventType(rawEvent),
      timestamp: new Date().toISOString(),
      payload: normalizePayload(rawEvent),
      metadata: extractMetadata(req)
    };

    // Match workflows
    const workflows = this.registry.findMatchingWorkflows(event);

    // Create run contexts
    for (const workflow of workflows) {
      const runContext = this.createRunContext(workflow, event);
      await this.orchestrator.queueRun(runContext);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Workflow Registry

Responsibilities:

  • Load workflow definitions
  • Validate JSON schema
  • Index for fast lookup

Implementation Pattern:

class WorkflowRegistry {
  private workflows: Map<string, Workflow> = new Map();

  async loadFromDirectory(path: string): Promise<void> {
    const files = await readdir(path);

    for (const file of files) {
      if (file.endsWith('.json')) {
        const workflow = await this.loadWorkflow(join(path, file));
        this.workflows.set(workflow.workflow_name, workflow);
      }
    }
  }

  findMatchingWorkflows(event: Event): Workflow[] {
    return Array.from(this.workflows.values())
      .filter(w => this.matchesTrigger(w.trigger, event));
  }

  private matchesTrigger(trigger: Trigger, event: Event): boolean {
    // Implement trigger matching logic
    return trigger.source === event.metadata.source &&
           trigger.type === event.event_type &&
           this.evaluateCondition(trigger.condition, event);
  }
}
Enter fullscreen mode Exit fullscreen mode

3. Orchestrator Core

Responsibilities:

  • Execute workflow steps in order
  • Manage run state
  • Handle branching logic

Implementation Pattern:

class Orchestrator {
  async executeWorkflow(runContext: RunContext): Promise<void> {
    const { workflow, run_state } = runContext;

    // Initial ledger entry
    await this.ledger.logEvent('workflow_triggered', run_state);

    try {
      for (const step of workflow.steps) {
        // Check if should run
        const shouldRun = this.evaluateShouldRun(
          step.binary_logic.should_run_expr,
          run_state
        );

        if (!shouldRun) {
          continue;
        }

        // Execute step
        run_state.current_step = [step.id](http://step.id);
        const result = await this.executeStep(step, run_state);

        // Store result
        run_state.step_results[[step.id](http://step.id)] = result;

        // Log if configured
        if (step.binary_logic.log_to_ledger) {
          await this.ledger.logEvent('step_completed', run_state, step);
        }

        // Handle result
        if (result.status === 'failed') {
          await this.handleFailure(step, run_state);
          return; // May halt or continue based on on_failure
        }
      }

      // Success
      run_state.status = 'completed';
      await this.ledger.logEvent('workflow_completed', run_state);

    } catch (error) {
      run_state.status = 'failed';
      run_state.error = error;
      await this.ledger.logEvent('workflow_failed', run_state);
      throw error;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Connector Layer

Responsibilities:

  • Abstract external APIs
  • Handle authentication
  • Retry logic
  • Error mapping

Implementation Pattern:

interface ServiceConnector {
  execute(action: string, inputs: any, context: RunContext): Promise<any>;
}

class GmailConnector implements ServiceConnector {
  async execute(action: string, inputs: any, context: RunContext): Promise<any> {
    switch (action) {
      case 'send_email':
        return await this.sendEmail(inputs, context);
      case 'create_draft':
        return await this.createDraft(inputs, context);
      default:
        throw new Error(`Unknown action: ${action}`);
    }
  }

  private async sendEmail(inputs: any, context: RunContext): Promise<any> {
    const { to, subject, body } = inputs;

    // Add correlation ID to headers
    const headers = {
      'X-Correlation-ID': context.correlation_id
    };

    // Call Gmail API with retry
    const result = await this.retryWithBackoff(() =>
      this.gmailClient.users.messages.send({
        userId: 'me',
        requestBody: {
          raw: this.encodeEmail({ to, subject, body, headers })
        }
      })
    );

    return {
      message_id: [result.data.id](http://result.data.id)
    };
  }
}
Enter fullscreen mode Exit fullscreen mode

5. Ledger System

Responsibilities:

  • Format ledger emails
  • Send to Gmail
  • Apply labels
  • Track message IDs

Implementation Pattern:

class LedgerSystem {
  async logEvent(
    event_type: string,
    run_state: RunState,
    step?: Step
  ): Promise<void> {
    const workflow = run_state.workflow;

    // Check if should log this event
    if (![workflow.gmail](http://workflow.gmail)_ledger.log_events.includes(event_type)) {
      return;
    }

    // Format subject
    const subject = this.formatSubject(
      [workflow.gmail](http://workflow.gmail)_ledger.subject_template,
      { workflow, event_type, run_state }
    );

    // Format body
    const body = this.formatBody(
      [workflow.gmail](http://workflow.gmail)_ledger.body_template,
      { workflow, event_type, run_state, step }
    );

    // Send email
    const result = await this.gmailConnector.execute('send_email', {
      to: [workflow.gmail](http://workflow.gmail)_ledger.ledger_recipient,
      subject,
      body
    }, run_state);

    // Track message ID
    run_state.ledger_emails_sent.push(result.message_id);

    // Apply labels
    await this.applyLabels(result.message_id, workflow, event_type);
  }
}
Enter fullscreen mode Exit fullscreen mode

PROMPT 3 — The Ledger System (Gmail OS Explanation)

Philosophy: Logs as Email

Why Email for Logging?

Traditional logging approaches have fundamental limitations:

File-based logs:

  • Require filesystem access
  • Rotation and retention are manual
  • No built-in search
  • Siloed per server
  • Lost when servers are destroyed

Database logs:

  • Require DB schema
  • Query performance degrades over time
  • Backup and retention require separate systems
  • Access requires DB credentials

Logging services (Datadog, Splunk, etc.):

  • Expensive at scale
  • Proprietary formats
  • Vendor lock-in
  • Complex query languages

Gmail as a logging system provides:

  1. Durability: Google's infrastructure, automatic backup
  2. Search: Powerful, fast, familiar search interface
  3. Organization: Labels act as hierarchical directories
  4. Access Control: Gmail's native permissions
  5. Retention: Configurable per label
  6. Cost: Free up to 15GB per account
  7. Accessibility: Any service can read/write via API
  8. Human + Machine: Both readable in same format
  9. Threading: Related events automatically grouped
  10. Time-based queries: Built-in date filters

The Paradigm Shift

Traditional: Logs are a side effect of execution

Mind's Eye: Logs ARE the execution record

In Mind's Eye:

  • Every significant state change → ledger entry
  • The ledger is queryable as a database
  • The ledger enables replay and audit
  • The ledger feeds the Hunting Engine
  • The ledger is the source of truth

Email threading creates natural grouping:

Thread: Invoice INV-001 Processing
├─ [LEDGER] workflow=invoice-intake event=workflow_triggered
├─ [LEDGER] workflow=invoice-intake event=step_completed (validation)
├─ [LEDGER] workflow=invoice-intake event=step_completed (doc creation)
├─ [LEDGER] workflow=invoice-intake event=step_completed (docket creation)
└─ [LEDGER] workflow=invoice-intake event=workflow_completed
Enter fullscreen mode Exit fullscreen mode

Ledger Event Structure

Subject Format (Machine-Readable)

[LEDGER] workflow={workflow_name} event={event_type} cid={correlation_id}
Enter fullscreen mode Exit fullscreen mode

Components:

  • [LEDGER]: Prefix for all ledger emails (enables quick filtering)
  • workflow={name}: Which workflow generated this event
  • event={type}: What happened (workflow_triggered, step_completed, error, etc.)
  • cid={uuid}: Correlation ID linking all events in this workflow run

Examples:

[LEDGER] workflow=invoice-intake-and-validation event=workflow_triggered cid=550e8400-e29b-41d4-a716-446655440000

[LEDGER] workflow=invoice-intake-and-validation event=step_completed cid=550e8400-e29b-41d4-a716-446655440000

[LEDGER] workflow=duplicate-invoice-review event=validation_failed cid=7f2b0c50-f3e1-4b99-8a47-5d6c8b9e3a12

[LEDGER] workflow=meeting-notes-workflow event=error cid=9c4d1e60-a4f2-5c88-9b58-6e7d9c0f4b23
Enter fullscreen mode Exit fullscreen mode

Body Format (Structured Template)

========================================
MIND'S EYE WORKFLOW LEDGER ENTRY
========================================

WORKFLOW: {workflow_name}
EVENT: {event_type}
CORRELATION_ID: {correlation_id}
RUN_ID: {run_id}
TIMESTAMP: {iso_timestamp}

========================================
TRIGGER INFORMATION
========================================

SOURCE: {trigger.source}
TYPE: {trigger.event_type}
TIMESTAMP: {trigger.timestamp}

PAYLOAD:
{trigger.payload | json_pretty_print}

========================================
STEP INFORMATION
========================================

STEP_ID: {[step.id](http://step.id)}
SERVICE: {step.service}
ACTION: {step.action}
STATUS: {step_status}

INPUTS:
{step.inputs | json_pretty_print}

RESOLVED INPUTS (after template substitution):
{resolved_inputs | json_pretty_print}

OUTPUTS:
{step.outputs | json_pretty_print}

EXECUTION TIME: {step_duration_ms}ms

========================================
WORKFLOW STATE
========================================

CURRENT_STEP: {current_step_number} of {total_steps}
STATUS: {workflow_status}
STEPS_COMPLETED: {completed_steps}
STEPS_REMAINING: {remaining_steps}

STEP RESULTS SUMMARY:
{step_results_summary}

========================================
ERROR INFORMATION
========================================

ERROR: {error_message | default: "none"}
STACK TRACE:
{error_stack | default: "N/A"}

RECOVERY ACTION: {on_failure_action}

========================================
LEDGER METADATA
========================================

LEDGER_EMAIL_COUNT: {total_ledger_emails_for_this_run}
WORKFLOW_START_TIME: {workflow_start_timestamp}
ELAPSED_TIME: {elapsed_ms}ms

CORRELATION_ID: {correlation_id}
QUERY THIS RUN: gmail search "cid={correlation_id}"

========================================
END LEDGER ENTRY
========================================
Enter fullscreen mode Exit fullscreen mode

Correlation IDs: Complete Traceability

How Correlation IDs Work

1. Generation

const correlation_id = crypto.randomUUID();
// Example: "550e8400-e29b-41d4-a716-446655440000"
Enter fullscreen mode Exit fullscreen mode

2. Propagation

Every action in the workflow receives the correlation ID:

// In orchestrator
run_state.correlation_id = correlation_id;

// Passed to connectors
await connector.execute(action, inputs, {
  correlation_id: run_state.correlation_id
});

// Included in all ledger emails
subject: `[LEDGER] ... cid=${run_state.correlation_id}`

// Added to external system calls
headers: {
  'X-Correlation-ID': run_state.correlation_id
}
Enter fullscreen mode Exit fullscreen mode

3. Cross-Service Tracking

Google Form Submit
  ↓
MORCO Trigger (generates cid: abc-123)
  ↓
Step 1: Validate
  → Ledger Email: cid=abc-123
  ↓
Step 2: Create Google Doc
  → Doc metadata: correlation_id=abc-123
  → Ledger Email: cid=abc-123
  ↓
Step 3: Create WebDocket
  → Docket custom field: correlation_id=abc-123
  → Ledger Email: cid=abc-123
  ↓
Step 4: Send Gmail
  → Email header: X-Correlation-ID=abc-123
  → Ledger Email: cid=abc-123
Enter fullscreen mode Exit fullscreen mode

4. Complete Audit Trail Query

Gmail search: "cid=abc-123"

Results:
- 5 ledger emails
- Full trace from trigger to completion
- All inputs, outputs, and state at each step
- Timestamps showing duration
- Any errors that occurred
Enter fullscreen mode Exit fullscreen mode

Multi-Workflow Correlation

When workflows trigger other workflows:

{
  "correlation_id": "def-456",
  "parent_correlation_id": "abc-123",
  "workflow_chain": ["invoice-intake", "duplicate-review"]
}
Enter fullscreen mode Exit fullscreen mode

Queries:

// Find parent workflow
cid=abc-123

// Find child workflows
parent_cid=abc-123

// Find entire chain
cid=abc-123 OR parent_cid=abc-123
Enter fullscreen mode Exit fullscreen mode

Ledger Event Types

Core Event Types

workflow_created

  • When: Workflow definition is first registered
  • Payload: Complete workflow JSON
  • Use: Track workflow versions

2. workflow_triggered

  • When: Workflow execution starts
  • Payload: Trigger event, correlation ID, initial state
  • Use: Track workflow activations

3. step_completed

  • When: A step successfully executes
  • Payload: Step ID, inputs, outputs, duration
  • Use: Detailed execution trace

4. step_skipped

  • When: A step's should_run_expr evaluates to 0
  • Payload: Step ID, reason (expr result)
  • Use: Understand branching paths

5. validation_failed

  • When: Input validation fails
  • Payload: Failed fields, validation rules, errors
  • Use: Track data quality issues

6. error

  • When: Any error occurs (network, API, logic)
  • Payload: Error message, stack trace, step context
  • Use: Debugging, alerting

7. workflow_completed

  • When: Workflow successfully finishes
  • Payload: Final state, all outputs, total duration
  • Use: Success tracking, metrics

8. workflow_failed

  • When: Workflow terminates with error
  • Payload: Error details, partial state, recovery options
  • Use: Failure analysis

Hunting Engine Event Types

9. pattern_detected

  • When: A hunt finds a matching pattern
  • Payload: Hunt details, matched events, confidence
  • Use: Track discovered patterns

10. annotation_created

  • When: A hunt annotates an event
  • Payload: Annotation details, related events
  • Use: Enrichment tracking

11. hunt_run_completed

  • When: A hunt finishes analyzing a time window
  • Payload: Events analyzed, patterns found, duration
  • Use: Hunt performance metrics

Ledger Email Lifecycle

Phase 1: Event Generation

Orchestrator executes step
  ↓
Step completes successfully
  ↓
Check: step.binary_logic.log_to_ledger?
  ↓ (yes)
Check: [workflow.gmail](http://workflow.gmail)_ledger.log_events includes "step_completed"?
  ↓ (yes)
Generate ledger event
Enter fullscreen mode Exit fullscreen mode

Phase 2: Email Formatting

const subject = formatSubject({
  workflow_name: run_state.workflow_name,
  event_type: 'step_completed',
  correlation_id: run_state.correlation_id
});

const body = formatBody({
  workflow: run_state.workflow,
  event_type: 'step_completed',
  trigger: run_state.trigger,
  step: current_step,
  step_results: run_state.step_results,
  error: null
});
Enter fullscreen mode Exit fullscreen mode

Phase 3: Email Sending

await gmailConnector.execute('send_email', {
  to: [workflow.gmail](http://workflow.gmail)_ledger.ledger_recipient,
  subject: subject,
  body: body,
  headers: {
    'X-Correlation-ID': run_state.correlation_id,
    'X-Workflow': run_state.workflow_name,
    'X-Event-Type': 'step_completed'
  }
});
Enter fullscreen mode Exit fullscreen mode

Phase 4: Label Application

const labels = [
  'MORCO/Ledger',
  `MORCO/Workflows/${workflow_name}`,
  `MORCO/Events/${event_type}`,
  `MORCO/Status/${workflow_status}`
];

await gmailConnector.applyLabels(message_id, labels);
Enter fullscreen mode Exit fullscreen mode

Phase 5: Archival & Retention

Gmail's automatic features:

  • Stored durably in Google's infrastructure
  • Searchable via Gmail search
  • Can be archived (removed from inbox but kept)
  • Retention policies via label settings
  • Can be exported via Google Takeout

Optional: Secondary Archive

// Periodically export to cold storage
const ledger_emails = await fetchLedgerEmails({
  older_than: '90 days',
  label: 'MORCO/Ledger'
});

await exportToS3(ledger_emails);
await applyLabel(ledger_emails, 'MORCO/Archived');
Enter fullscreen mode Exit fullscreen mode

Querying the Ledger

Gmail Search Patterns

By Correlation ID:

subject:"cid=550e8400-e29b-41d4-a716-446655440000"
Enter fullscreen mode Exit fullscreen mode

By Workflow:

subject:"workflow=invoice-intake-and-validation"
Enter fullscreen mode Exit fullscreen mode

By Event Type:

subject:"event=step_completed"
Enter fullscreen mode Exit fullscreen mode

By Time Range:

subject:"[LEDGER]" after:2025/12/01 before:2025/12/31
Enter fullscreen mode Exit fullscreen mode

Errors Only:

subject:"event=error" OR subject:"event=workflow_failed"
Enter fullscreen mode Exit fullscreen mode

Specific Workflow + Errors:

subject:"workflow=invoice-intake" (subject:"event=error" OR subject:"event=validation_failed")
Enter fullscreen mode Exit fullscreen mode

By Label:

label:morco-workflows-invoice-intake
Enter fullscreen mode Exit fullscreen mode

Complex Query:

subject:"[LEDGER]" 
subject:"workflow=invoice-intake" 
after:2025/12/01 
-subject:"event=workflow_completed"
Enter fullscreen mode Exit fullscreen mode

(All invoice-intake runs in December that didn't complete)

Programmatic Queries

class LedgerQueryService {
  async getWorkflowRun(correlation_id: string): Promise<LedgerEmail[]> {
    const query = `subject:"cid=${correlation_id}" label:morco-ledger`;
    return await this.gmailClient.searchMessages(query);
  }

  async getRecentErrors(hours: number = 24): Promise<LedgerEmail[]> {
    const after = new Date([Date.now](http://Date.now)() - hours * 60 * 60 * 1000);
    const query = `
      subject:"[LEDGER]" 
      (subject:"event=error" OR subject:"event=workflow_failed")
      after:${this.formatDate(after)}
    `;
    return await this.gmailClient.searchMessages(query);
  }

  async getWorkflowMetrics(
    workflow_name: string,
    start: Date,
    end: Date
  ): Promise<WorkflowMetrics> {
    const query = `
      subject:"workflow=${workflow_name}" 
      subject:"event=workflow_completed"
      after:${this.formatDate(start)}
      before:${this.formatDate(end)}
    `;

    const emails = await this.gmailClient.searchMessages(query);

    return this.calculateMetrics(emails);
  }
}
Enter fullscreen mode Exit fullscreen mode

Analytics from Ledger Data

Parsing Ledger Emails

class LedgerParser {
  parseEmail(email: GmailMessage): LedgerEntry {
    const subject = email.subject;
    const body = email.body;

    // Parse subject
    const workflow_name = this.extractField(subject, 'workflow=');
    const event_type = this.extractField(subject, 'event=');
    const correlation_id = this.extractField(subject, 'cid=');

    // Parse body sections
    const trigger = this.extractSection(body, 'TRIGGER INFORMATION');
    const step = this.extractSection(body, 
'STEP INFORMATION');
    const status = this.extractSection(body, 'STATUS');
    const metadata = this.extractSection(body, 'METADATA');

    return {
      correlation_id,
      workflow_name,
      event_type,
      timestamp: email.timestamp,
      trigger,
      step,
      status,
      metadata
    };
  }

  private extractField(text: string, prefix: string): string {
    const regex = new RegExp(`${prefix}([^\\s]+)`);
    const match = text.match(regex);
    return match ? match[1] : '';
  }

  private extractSection(text: string, sectionName: string): any {
    const startMarker = `=== ${sectionName} ===`;
    const endMarker = '===';

    const startIdx = text.indexOf(startMarker);
    if (startIdx === -1) return null;

    const contentStart = startIdx + startMarker.length;
    const nextSectionIdx = text.indexOf(endMarker, contentStart);

    const sectionText = text.substring(contentStart, nextSectionIdx).trim();

    // Try to parse as JSON if it looks like structured data
    try {
      return JSON.parse(sectionText);
    } catch {
      return sectionText;
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Aggregating Metrics

class LedgerAnalytics {
  async getWorkflowMetrics(
    workflow_name: string,
    timeRange: { start: Date; end: Date }
  ): Promise<WorkflowMetrics> {
    // Fetch all completed runs
    const completedRuns = await this.ledgerQuery.getCompletedRuns(
      workflow_name,
      timeRange
    );

    // Fetch all failed runs
    const failedRuns = await this.ledgerQuery.getFailedRuns(
      workflow_name,
      timeRange
    );

    // Parse and aggregate
    const metrics = {
      total_runs: completedRuns.length + failedRuns.length,
      successful_runs: completedRuns.length,
      failed_runs: failedRuns.length,
      success_rate: completedRuns.length / (completedRuns.length + failedRuns.length),

      avg_duration: this.calculateAvgDuration(completedRuns),
      p50_duration: this.calculatePercentile(completedRuns, 0.5),
      p95_duration: this.calculatePercentile(completedRuns, 0.95),
      p99_duration: this.calculatePercentile(completedRuns, 0.99),

      error_breakdown: this.categorizeErrors(failedRuns),
      step_performance: this.analyzeStepPerformance(completedRuns)
    };

    return metrics;
  }

  async getStepErrorRate(
    workflow_name: string,
    step_id: string,
    days: number = 7
  ): Promise<number> {
    const query = `
      subject:"workflow=${workflow_name}"
      subject:"event=error"
      body:"STEP_ID: ${step_id}"
      after:${this.formatDate(daysAgo(days))}
    `;

    const errors = await this.gmailClient.searchMessages(query);
    const totalRuns = await this.getTotalRunsForWorkflow(workflow_name, days);

    return errors.length / totalRuns;
  }
}
Enter fullscreen mode Exit fullscreen mode

Visualization from Ledger

// Generate timeline visualization
const timeline = await ledgerAnalytics.getWorkflowTimeline(
  'invoice-intake-and-validation',
  { start: startDate, end: endDate }
);

// Output:
// 2025-12-01: ████████████ 12 runs (11 success, 1 fail)
// 2025-12-02: ██████████████████ 18 runs (18 success, 0 fail)
// 2025-12-03: ████████ 8 runs (7 success, 1 fail)
Enter fullscreen mode Exit fullscreen mode

When Ledger Emails Fire: Decision Matrix

Event Type When It Fires Always Logged? Configurable?
workflow_created Workflow registered in system Yes No
workflow_triggered Workflow execution starts If in log_events Yes
step_completed Step finishes successfully If in log_events AND step.binary_logic.log_to_ledger Yes (per step)
step_skipped should_run_expr = 0 If in log_events Yes
validation_failed Input validation fails If in log_events Yes
error Any error occurs Always No (critical)
workflow_completed Workflow finishes successfully If in log_events Yes
workflow_failed Workflow fails Always No (critical)

Best Practice: Always log workflow_triggered, step_completed, and workflow_completed for full traceability.


PROMPT 4 — Workflow Execution Model (The MORCO Runtime)

MORCO Runtime Overview

The MORCO Execution Runtime is the deterministic execution engine that takes workflow JSON specifications and executes them against real services. It's the heart of the Mind's Eye platform.

Core Responsibilities:

  1. Receive triggers from external sources
  2. Load workflow definitions from the registry
  3. Execute steps sequentially with conditional branching
  4. Resolve template variables using run state
  5. Call service connectors to perform actions
  6. Manage state across the entire workflow run
  7. Write ledger entries at key checkpoints
  8. Handle failures according to defined strategies

Step-by-Step Execution Flow

Phase 1: Trigger Reception

External Event (Form submit, Webhook, etc.)
  ↓
Ingestion Layer receives event
  ↓
Normalize to standard Event object
  ↓
Search Registry for matching workflows
  ↓
For each match: Create RunContext
Enter fullscreen mode Exit fullscreen mode

Code:

async handleTrigger(rawEvent: any): Promise<void> {
  // Normalize
  const event = this.normalizeEvent(rawEvent);

  // Find matching workflows
  const workflows = this.registry.findMatchingWorkflows(event);

  // Create run contexts
  for (const workflow of workflows) {
    const runContext = {
      run_id: generateUUID(),
      correlation_id: generateUUID(),
      workflow: workflow,
      trigger_event: event,
      run_state: this.initializeRunState(workflow, event)
    };

    // Queue for execution
    await this.executionQueue.enqueue(runContext);
  }
}
Enter fullscreen mode Exit fullscreen mode

Phase 2: Run State Initialization

initializeRunState(workflow: Workflow, event: Event): RunState {
  return {
    run_id: generateUUID(),
    correlation_id: generateUUID(),
    workflow_name: workflow.workflow_name,

    trigger: {
      event_id: event.event_id,
      event_type: event.event_type,
      payload: event.payload,
      timestamp: event.timestamp
    },

    step_results: {},
    current_step: null,
    status: 'queued',

    created_at: new Date().toISOString(),
    ledger_emails_sent: [],

    metadata: {
      workflow_version: workflow.version || '1.0.0',
      entry_point: workflow.entry_point
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

Phase 3: Orchestration Loop

This is the core execution algorithm:

async executeWorkflow(runContext: RunContext): Promise<void> {
  const { workflow, run_state } = runContext;

  // Update status
  run_state.status = 'running';
  run_state.started_at = new Date().toISOString();

  // Log workflow start
  await this.ledger.logEvent('workflow_triggered', run_state);

  try {
    // Execute each step
    for (let i = 0; i < workflow.steps.length; i++) {
      const step = workflow.steps[i];
      run_state.current_step = [step.id](http://step.id);

      // === STEP 1: Evaluate Should Run ===
      const shouldRun = this.evaluateShouldRun(
        step.binary_logic.should_run_expr,
        run_state
      );

      if (!shouldRun) {
        // Log skip
        if ([workflow.gmail](http://workflow.gmail)_ledger.log_events.includes('step_skipped')) {
          await this.ledger.logEvent('step_skipped', run_state, step);
        }
        continue;
      }

      // === STEP 2: Resolve Template Variables ===
      const resolvedInputs = this.resolveTemplates(
        step.inputs,
        run_state
      );

      // === STEP 3: Execute Connector ===
      const startTime = [Date.now](http://Date.now)();
      let stepResult: StepResult;

      try {
        const connector = this.connectorFactory.getConnector(step.service);
        const outputs = await connector.execute(
          step.action,
          resolvedInputs,
          runContext
        );

        stepResult = {
          outputs,
          status: 'success',
          started_at: new Date(startTime).toISOString(),
          completed_at: new Date().toISOString(),
          duration_ms: [Date.now](http://Date.now)() - startTime
        };

      } catch (error) {
        stepResult = {
          outputs: null,
          status: 'failed',
          error: error.message,
          stack: error.stack,
          started_at: new Date(startTime).toISOString(),
          completed_at: new Date().toISOString(),
          duration_ms: [Date.now](http://Date.now)() - startTime
        };
      }

      // === STEP 4: Store Result ===
      run_state.step_results[[step.id](http://step.id)] = stepResult;

      // === STEP 5: Log if Configured ===
      if (step.binary_logic.log_to_ledger) {
        await this.ledger.logEvent('step_completed', run_state, step);
      }

      // === STEP 6: Handle Result ===
      if (stepResult.status === 'failed') {
        await this.handleStepFailure(step, run_state);

        // Check on_failure strategy
        if (step.binary_logic.on_failure === 'halt workflow') {
          throw new Error(`Step ${[step.id](http://step.id)} failed: ${stepResult.error}`);
        } else if (step.binary_logic.on_failure.startsWith('jump to')) {
          const targetStep = step.binary_logic.on_failure.match(/jump to (\\w+)/)[1];
          i = workflow.steps.findIndex(s => [s.id](http://s.id) === targetStep) - 1;
          continue;
        }
        // else: continue to next step
      } else {
        // Success path
        if (step.binary_logic.on_success.startsWith('jump to')) {
          const targetStep = step.binary_logic.on_success.match(/jump to (\\w+)/)[1];
          i = workflow.steps.findIndex(s => [s.id](http://s.id) === targetStep) - 1;
        }
        // else: continue to next step (default)
      }
    }

    // Workflow completed successfully
    run_state.status = 'completed';
    run_state.completed_at = new Date().toISOString();
    await this.ledger.logEvent('workflow_completed', run_state);

  } catch (error) {
    // Workflow failed
    run_state.status = 'failed';
    run_state.completed_at = new Date().toISOString();
    run_state.error = {
      step_id: run_state.current_step,
      message: error.message,
      stack: error.stack
    };

    await this.ledger.logEvent('workflow_failed', run_state);
    throw error;
  }
}
Enter fullscreen mode Exit fullscreen mode

Binary Logic: should_run_expr Deep Dive

The Expression Language

Mind's Eye uses a safe subset of JavaScript expressions for should_run_expr. This allows powerful conditional logic while preventing code injection.

Supported Operators:

  • Comparison: ==, !=, >, <, >=, <=
  • Logical: &&, ||, !
  • Arithmetic: +, -, *, /, %
  • Literals: true, false, numbers, strings (single/double quotes)
  • Variable access: Dot notation for nested paths

Supported Variables:

  • trigger.*: Access trigger payload fields
  • step_N.outputs.*: Access outputs from previous steps
  • step_N.status: Check if step succeeded or failed

Evaluation Engine

class BinaryLogicEvaluator {
  evaluateShouldRun(expr: string, runState: RunState): boolean {
    // Handle simple cases
    if (expr === '1' || expr === 'true') return true;
    if (expr === '0' || expr === 'false') return false;

    // Resolve all variable references
    const resolved = this.resolveVariables(expr, runState);

    // If resolution resulted in a boolean, return it
    if (typeof resolved === 'boolean') return resolved;

    // Otherwise, safely evaluate the expression
    return this.safeEval(resolved);
  }

  private resolveVariables(expr: string, runState: RunState): any {
    // Replace trigger references
    expr = expr.replace(/trigger\\.([a-zA-Z0-9_.\\[\\]]+)/g, (match, path) => {
      const value = this.getNestedValue(runState.trigger.payload, path);
      return JSON.stringify(value);
    });

    // Replace step references
    expr = expr.replace(/step_([a-zA-Z0-9_]+)\\.outputs\\.([a-zA-Z0-9_.\\[\\]]+)/g, 
      (match, stepId, path) => {
        const stepResult = runState.step_results[`step_${stepId}`];
        if (!stepResult) return 'null';
        const value = this.getNestedValue(stepResult.outputs, path);
        return JSON.stringify(value);
      });

    // Replace step status references
    expr = expr.replace(/step_([a-zA-Z0-9_]+)\\.status/g, (match, stepId) => {
      const stepResult = runState.step_results[`step_${stepId}`];
      return stepResult ? `"${stepResult.status}"` : '"unknown"';
    });

    return expr;
  }

  private safeEval(expr: string): boolean {
    // Use a safe expression evaluator (like expr-eval library)
    // or implement a simple recursive descent parser
    const parser = new ExpressionParser();
    const result = parser.parse(expr).evaluate();
    return Boolean(result);
  }

  private getNestedValue(obj: any, path: string): any {
    return path.split('.').reduce((current, key) => {
      if (current === null || current === undefined) return null;
      return current[key];
    }, obj);
  }
}
Enter fullscreen mode Exit fullscreen mode

Examples with Evaluation

Example 1: Simple Boolean

{
  "should_run_expr": "[trigger.is](http://trigger.is)_urgent"
}
Enter fullscreen mode Exit fullscreen mode
// Evaluation:
trigger.payload = { is_urgent: true, ... }
resolveVariables("[trigger.is](http://trigger.is)_urgent", runState)
   true
return true  // Step runs
Enter fullscreen mode Exit fullscreen mode

Example 2: Comparison

{
  "should_run_expr": "trigger.amount > 5000"
}
Enter fullscreen mode Exit fullscreen mode
// Evaluation:
trigger.payload = { amount: 7500, ... }
resolveVariables("trigger.amount > 5000", runState)
   "7500 > 5000"
safeEval("7500 > 5000")
   true
return true  // Step runs
Enter fullscreen mode Exit fullscreen mode

Example 3: Dependent on Previous Step

{
  "should_run_expr": "step_[1.outputs.is](http://1.outputs.is)_valid && trigger.amount > 1000"
}
Enter fullscreen mode Exit fullscreen mode
// Evaluation:
step_results = {
  step_1: { outputs: { is_valid: true }, status: 'success' }
}
trigger.payload = { amount: 2000, ... }

resolveVariables("step_[1.outputs.is](http://1.outputs.is)_valid && trigger.amount > 1000", runState)
   "true && 2000 > 1000"
safeEval("true && 2000 > 1000")
   true
return true  // Step runs
Enter fullscreen mode Exit fullscreen mode

Example 4: String Comparison

{
  "should_run_expr": "trigger.status == 'approved' || trigger.status == 'completed'"
}
Enter fullscreen mode Exit fullscreen mode
// Evaluation:
trigger.payload = { status: 'approved', ... }
resolveVariables("trigger.status == 'approved' || trigger.status == 'completed'", runState)
   "\"approved\" == 'approved' || \"approved\" == 'completed'"
safeEval("\"approved\" == 'approved' || \"approved\" == 'completed'")
   true
return true  // Step runs
Enter fullscreen mode Exit fullscreen mode

Template Resolution: Dynamic Input Binding

The Template Syntax

Templates use dotted path notation to reference values from the run state:

Syntax:

  • trigger.field_name: Access trigger payload
  • step_N.outputs.field_name: Access previous step outputs
  • step_N.status: Access step execution status

No templating engine needed — simple string replacement and path resolution.

Resolution Algorithm

class TemplateResolver {
  resolveTemplates(inputs: any, runState: RunState): any {
    if (typeof inputs === 'string') {
      return this.resolveString(inputs, runState);
    } else if (Array.isArray(inputs)) {
      return [inputs.map](http://inputs.map)(item => this.resolveTemplates(item, runState));
    } else if (typeof inputs === 'object' && inputs !== null) {
      const resolved = {};
      for (const [key, value] of Object.entries(inputs)) {
        resolved[key] = this.resolveTemplates(value, runState);
      }
      return resolved;
    } else {
      return inputs;
    }
  }

  private resolveString(template: string, runState: RunState): any {
    // Check if the entire string is a template reference
    if (this.isTemplateReference(template)) {
      return this.resolveReference(template, runState);
    }

    // Otherwise, perform string interpolation
    return template.replace(/\\{\\{([^}]+)\\}\\}/g, (match, path) => {
      const value = this.resolveReference(path.trim(), runState);
      return String(value);
    });
  }

  private isTemplateReference(str: string): boolean {
    return /^(trigger|step_\\w+)\\.[a-zA-Z0-9_.\\[\\]]+$/.test(str);
  }

  private resolveReference(path: string, runState: RunState): any {
    if (path.startsWith('trigger.')) {
      const fieldPath = path.substring(8); // Remove 'trigger.'
      return this.getNestedValue(runState.trigger.payload, fieldPath);
    } else if (path.startsWith('step_')) {
      const match = path.match(/^step_([a-zA-Z0-9_]+)\\.(.+)$/);
      if (!match) return null;

      const [, stepId, fieldPath] = match;
      const stepResult = runState.step_results[`step_${stepId}`];
      if (!stepResult) return null;

      return this.getNestedValue(stepResult, fieldPath);
    }

    return null;
  }

  private getNestedValue(obj: any, path: string): any {
    return path.split('.').reduce((current, key) => {
      if (current === null || current === undefined) return null;
      // Handle array indices: field[0]
      const arrayMatch = key.match(/^([^\\[]+)\\[(\\d+)\\]$/);
      if (arrayMatch) {
        const [, arrayKey, index] = arrayMatch;
        return current[arrayKey] ? current[arrayKey][parseInt(index)] : null;
      }
      return current[key];
    }, obj);
  }
}
Enter fullscreen mode Exit fullscreen mode

Template Resolution Examples

Example 1: Simple Field Reference

{
  "step_3": {
    "inputs": {
      "recipient": "trigger.submitter_email",
      "subject": "Invoice Received"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
// Before resolution:
inputs = {
  recipient: "trigger.submitter_email",
  subject: "Invoice Received"
}

// After resolution:
runState.trigger.payload = { submitter_email: "[vendor@acme.com](mailto:vendor@acme.com)", ... }

resolvedInputs = {
  recipient: "[vendor@acme.com](mailto:vendor@acme.com)",
  subject: "Invoice Received"
}
Enter fullscreen mode Exit fullscreen mode

Example 2: Nested Object Reference

{
  "step_4": {
    "inputs": {
      "doc_url": "step_2.outputs.doc_url",
      "docket_id": "step_3.outputs.docket_id"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
// Before resolution:
inputs = {
  doc_url: "step_2.outputs.doc_url",
  docket_id: "step_3.outputs.docket_id"
}

// After resolution:
runState.step_results = {
  step_2: { outputs: { doc_url: "https://docs.google.com/..." } },
  step_3: { outputs: { docket_id: "DOCK-001" } }
}

resolvedInputs = {
  doc_url: "https://docs.google.com/...",
  docket_id: "DOCK-001"
}
Enter fullscreen mode Exit fullscreen mode

Example 3: String Interpolation

{
  "step_5": {
    "inputs": {
      "subject": "Invoice trigger.invoice_number - step_1.outputs.validation_status",
      "body": "Invoice from trigger.vendor_name has been step_1.outputs.validation_status"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode
// Before resolution:
inputs = {
  subject: "Invoice trigger.invoice_number - step_1.outputs.validation_status",
  body: "Invoice from trigger.vendor_name has been step_1.outputs.validation_status"
}

// After resolution:
runState.trigger.payload = { invoice_number: "INV-001", vendor_name: "Acme Corp" }
runState.step_results = {
  step_1: { outputs: { validation_status: "approved" } }
}

resolvedInputs = {
  subject: "Invoice INV-001 - approved",
  body: "Invoice from Acme Corp has been approved"
}
Enter fullscreen mode Exit fullscreen mode

Connector Execution

Connector Interface

All connectors implement this interface:

interface ServiceConnector {
  /**
   * Execute an action on this service
   * @param action The action to perform (e.g., 'send_email', 'create_doc')
   * @param inputs The resolved inputs for this action
   * @param context The full run context for correlation tracking
   * @returns The outputs from the action
   */
  execute(action: string, inputs: any, context: RunContext): Promise<any>;
}
Enter fullscreen mode Exit fullscreen mode

Connector Responsibilities

  1. Action Routing: Map action string to internal method
  2. Authentication: Handle OAuth, API keys, service accounts
  3. Input Validation: Ensure required fields are present
  4. API Calls: Make actual HTTP requests to external services
  5. Retry Logic: Retry failed requests with exponential backoff
  6. Rate Limiting: Respect API rate limits
  7. Error Handling: Map service errors to standardized format
  8. Output Mapping: Return consistent output structure
  9. Correlation Tracking: Include correlation ID in requests

Example: Gmail Connector

class GmailConnector implements ServiceConnector {
  constructor(
    private gmailClient: GmailClient,
    private retryConfig: RetryConfig
  ) {}

  async execute(action: string, inputs: any, context: RunContext): Promise<any> {
    // Route to action handler
    switch (action) {
      case 'send_email':
        return await this.sendEmail(inputs, context);
      case 'create_draft':
        return await this.createDraft(inputs, context);
      case 'add_label':
        return await this.addLabel(inputs, context);
      default:
        throw new Error(`Unknown Gmail action: ${action}`);
    }
  }

  private async sendEmail(inputs: any, context: RunContext): Promise<any> {
    // Validate inputs
    this.validateRequired(inputs, ['to', 'subject', 'body']);

    // Prepare email
    const email = {
      to: [inputs.to](http://inputs.to),
      from: inputs.from || this.config.defaultFrom,
      subject: inputs.subject,
      body: inputs.body,
      cc: [inputs.cc](http://inputs.cc),
      bcc: inputs.bcc,
      attachments: inputs.attachments
    };

    // Add correlation ID header
    const headers = {
      'X-Correlation-ID': context.correlation_id,
      'X-Workflow': [context.run](http://context.run)_state.workflow_name,
      'X-Run-ID': [context.run](http://context.run)_id,
      ...(inputs.headers || {})
    };

    // Send with retry
    const result = await this.retryWithBackoff(async () => {
      return await this.gmailClient.users.messages.send({
        userId: 'me',
        requestBody: {
          raw: this.encodeEmail({ ...email, headers })
        }
      });
    });

    // Return outputs
    return {
      message_id: [result.data.id](http://result.data.id),
      thread_id: [result.data](http://result.data).threadId,
      sent_at: new Date().toISOString()
    };
  }

  private async retryWithBackoff<T>(
    fn: () => Promise<T>,
    maxRetries: number = 3
  ): Promise<T> {
    let lastError: Error;

    for (let attempt = 0; attempt <= maxRetries; attempt++) {
      try {
        return await fn();
      } catch (error) {
        lastError = error;

        // Don't retry on client errors (4xx)
        if (error.code >= 400 && error.code < 500) {
          throw error;
        }

        if (attempt < maxRetries) {
          const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
          await this.sleep(delay);
        }
      }
    }

    throw lastError;
  }

  private validateRequired(inputs: any, required: string[]): void {
    const missing = required.filter(field => !(field in inputs));
    if (missing.length > 0) {
      throw new Error(`Missing required fields: ${missing.join(', ')}`);
    }
  }

  private encodeEmail(email: any): string {
    // Implement RFC 2822 email encoding
    // ... encoding logic ...
    return Buffer.from(encoded).toString('base64url');
  }
}
Enter fullscreen mode Exit fullscreen mode

Failure Handling Strategies

on_failure Options

1. halt workflow (Default for critical steps)

{
  "on_failure": "halt workflow"
}
Enter fullscreen mode Exit fullscreen mode
  • Stops execution immediately
  • Marks workflow as failed
  • Writes workflow_failed ledger entry
  • Error details captured in run state

2. log error and continue

{
  "on_failure": "log error and continue"
}
Enter fullscreen mode Exit fullscreen mode
  • Logs the error to ledger
  • Continues to next step
  • Subsequent steps can check step_N.status == 'failed'

3. jump to <step_id>

{
  "on_failure": "jump to step_error_handler"
}
Enter fullscreen mode Exit fullscreen mode
  • Skips remaining steps
  • Jumps directly to specified error handling step
  • Error details available in run state

4. trigger workflow <workflow_name>

{
  "on_failure": "trigger workflow error-notification-workflow"
}
Enter fullscreen mode Exit fullscreen mode
  • Creates a new workflow run
  • Passes error details as trigger payload
  • Original workflow continues or halts based on secondary config

Error Context Propagation

When a step fails, the error context is stored:

stepResult = {
  outputs: null,
  status: 'failed',
  error: {
    message: "Gmail API error: Invalid recipient",
    code: "INVALID_RECIPIENT",
    details: {
      recipient: "invalid-email",
      api_response: {...}
    },
    stack: "Error: Gmail API error\\n  at GmailConnector.sendEmail..."
  }
}
Enter fullscreen mode Exit fullscreen mode

Subsequent steps can access this:

{
  "step_error_handler": {
    "inputs": {
      "error_message": "step_3.error.message",
      "failed_step": "step_3",
      "original_inputs": "step_3.inputs"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Data Flow Between Steps

The Step Results Chain

Step 1: Validate
  ↓ outputs: { is_valid: true, normalized_data: {...} }

Step 2: Create Doc (uses Step 1 outputs)
  ↓ inputs: { data: "step_1.outputs.normalized_data" }
  ↓ outputs: { doc_id: "abc123", doc_url: "https://..." }

Step 3: Create Docket (uses Step 2 outputs)
  ↓ inputs: { doc_url: "step_2.outputs.doc_url" }
  ↓ outputs: { docket_id: "DOCK-001", docket_url: "https://..." }

Step 4: Send Email (uses outputs from Steps 2 & 3)
  ↓ inputs: {
      body: "Doc: step_2.outputs.doc_url, Docket: step_3.outputs.docket_url"
    }
  ↓ outputs: { message_id: "msg123" }
Enter fullscreen mode Exit fullscreen mode

Data Transformation Pipeline

Sometimes you need to transform data between steps:

Option 1: Connector Handles Transformation

{
  "step_2": {
    "service": "google_docs",
    "action": "create_doc_from_template",
    "inputs": {
      "template_id": "template123",
      "replacements": {
        "vendor": "trigger.vendor_name",
        "amount": "trigger.amount",
        "date": "trigger.due_date"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Option 2: Use Formula/Expression Step (Future Enhancement)

{
  "step_1_5": {
    "service": "transform",
    "action": "evaluate",
    "inputs": {
      "expression": "step_1.outputs.amount * 1.15",
      "output_field": "amount_with_tax"
    },
    "outputs": {
      "amount_with_tax": "number"
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Complete Execution Diagram with Data Flow

┌────────────────────────────────────────────────────────────────────┐
│                       WORKFLOW EXECUTION                           │
└────────────────────────────────────────────────────────────────────┘

TRIGGER EVENT
{ vendor_name: "Acme", invoice_number: "INV-001", amount: 5000 }
  ↓
┌──────────────────────────────────────────────────────────────────┐
│ INITIALIZE RUN STATE                                             │
│ • run_id: uuid                                                   │
│ • correlation_id: uuid                                           │
│ • trigger: { ... }                                               │
│ • step_results: {}                                               │
│ • status: 'running'                                              │
└──────────────────────────────────────────────────────────────────┘
  ↓
┌──────────────────────────────────────────────────────────────────┐
│ STEP 1: VALIDATE INVOICE                                         │
│ should_run_expr: "1" → evaluates to TRUE                         │
│ inputs (resolved):                                               │
│   • submission: { vendor_name: "Acme", ... }                     │
│ ──────────────────────────────────────────────────────────────── │
│ CONNECTOR: google_forms.validate_submission()                    │
│ ──────────────────────────────────────────────────────────────── │
│ outputs:                                                          │
│   • is_valid: true                                               │
│   • normalized_payload: { ... }                                  │
│ ──────────────────────────────────────────────────────────────── │
│ STORE: step_results['step_1'] = { outputs: {...}, status: 'success' } │
│ LOG: ledger email "step_completed"                               │
└──────────────────────────────────────────────────────────────────┘
  ↓
┌──────────────────────────────────────────────────────────────────┐
│ STEP 2: CREATE GOOGLE DOC                                        │
│ should_run_expr: "step_[1.outputs.is](http://1.outputs.is)_valid" → TRUE               │
│ inputs (before resolution):                                      │
│   • data: "step_1.outputs.normalized_payload"                    │
│ inputs (after resolution):                                       │
│   • data: { vendor_name: "Acme", ... }                           │
│ ──────────────────────────────────────────────────────────────── │
│ CONNECTOR: google_docs.create_doc_from_template()                │
│ ──────────────────────────────────────────────────────────────── │
│ outputs:                                                          │
│   • doc_id: "1abc123def"                                         │
│   • doc_url: "https://docs.google.com/document/d/1abc123def"     │
│ ──────────────────────────────────────────────────────────────── │
│ STORE: step_results['step_2'] = { outputs: {...}, status: 'success' } │
│ LOG: ledger email "step_completed"                               │
└──────────────────────────────────────────────────────────────────┘
  ↓
┌──────────────────────────────────────────────────────────────────┐
│ STEP 3: CREATE WEBDOCKET                                         │
│ should_run_expr: "1" → TRUE                                      │
│ inputs (before resolution):                                      │
│   • title: "Invoice: trigger.invoice_number"                     │
│   • doc_url: "step_2.outputs.doc_url"                            │
│ inputs (after resolution):                                       │
│   • title: "Invoice: INV-001"                                    │
│   • doc_url: "https://docs.google.com/document/d/1abc123def"     │
│ ──────────────────────────────────────────────────────────────── │
│ CONNECTOR: webdocket.create_docket()                             │
│ ──────────────────────────────────────────────────────────────── │
│ outputs:                                                          │
│   • docket_id: "DOCK-001"                                        │
│   • docket_url: "https://webdocket.com/docket/DOCK-001"          │
│ ──────────────────────────────────────────────────────────────── │
│ STORE: step_results['step_3'] = { outputs: {...}, status: 'success' } │
│ LOG: ledger email "step_completed"                               │
└──────────────────────────────────────────────────────────────────┘
  ↓
┌──────────────────────────────────────────────────────────────────┐
│ STEP 4: SEND NOTIFICATION EMAIL                                  │
│ should_run_expr: "1" → TRUE                                      │
│ inputs (before resolution):                                      │
│   • to: "[finance@company.com](mailto:finance@company.com)"                                    │
│   • subject: "Invoice trigger.invoice_number Processed"          │
│   • body: "Doc: step_2.outputs.doc_url\\nDocket: step_3.outputs.docket_url" │
│ inputs (after resolution):                                       │
│   • to: "[finance@company.com](mailto:finance@company.com)"                                    │
│   • subject: "Invoice INV-001 Processed"                         │
│   • body: "Doc: https://docs.google.com/...\\nDocket: https://webdocket.com/..." │
│ ──────────────────────────────────────────────────────────────── │
│ CONNECTOR: gmail.send_email()                                    │
│ ──────────────────────────────────────────────────────────────── │
│ outputs:                                                          │
│   • message_id: "msg789xyz"                                      │
│ ──────────────────────────────────────────────────────────────── │
│ STORE: step_results['step_4'] = { outputs: {...}, status: 'success' } │
│ LOG: ledger email "step_completed"                               │
└──────────────────────────────────────────────────────────────────┘
  ↓
┌──────────────────────────────────────────────────────────────────┐
│ WORKFLOW COMPLETE                                                │
│ • status: 'completed'                                            │
│ • completed_at: timestamp                                        │
│ • all steps succeeded                                            │
│ LOG: ledger email "workflow_completed"                           │
└──────────────────────────────────────────────────────────────────┘
  ↓
GMAIL LEDGER
5 emails sent with correlation_id
Queryable for complete audit trail
Enter fullscreen mode Exit fullscreen mode

PROMPT 5 — Workflow JSON Specification (Official Schema)

Schema Overview

This is the canonical specification for Mind's Eye MORCO workflow definitions. All workflows must conform to this schema.

Schema Version: 1.0.0

Format: JSON

Encoding: UTF-8

Top-Level Workflow Object

interface Workflow {
  // Required fields
  workflow_name: string;
  description: string;
  entry_point: 'google_form' | 'webdocket' | 'chatbot' | 'cron' | 'hunting_engine';
  trigger: Trigger;
  steps: Step[];

  // Optional fields
  gmail_ledger?: GmailLedger;
  version?: string;
  author?: string;
  tags?: string[];
  metadata?: Record<string, any>;
}
Enter fullscreen mode Exit fullscreen mode

Field Specifications

workflow_name (required)

Type: string

Format: Lowercase, kebab-case

Pattern: ^[a-z0-9]+(-[a-z0-9]+)*$

Max Length: 100 characters

Description: Unique identifier for the workflow. Must be stable across versions.

Valid Examples:

  • invoice-intake-and-validation
  • meeting-notes-workflow
  • duplicate-invoice-review

Invalid Examples:

  • Invoice Intake (contains spaces, not lowercase)
  • invoice_intake (uses underscores, should be hyphens)
  • workflow-123-ABC (contains uppercase)

description (required)

Type: string

Max Length: 500 characters

Description: Human-readable explanation of what the workflow does, its trigger conditions, and expected outcomes. Should include any assumptions.

Example:

{
  "description": "Triggered when a vendor submits an invoice through the finance invoice form. Validates required fields, creates a structured Google Doc invoice record, creates a WebDocket entry for tracking, notifies the finance team, and logs all key events to the Gmail ledger. Assumes a dedicated invoice intake form and a shared finance notification email."
}
Enter fullscreen mode Exit fullscreen mode

entry_point (required)

Type: enum

Allowed Values:

  • google_form: Triggered by Google Form submission
  • webdocket: Triggered by WebDocket event (created, updated, status changed)
  • chatbot: Triggered by conversational AI interaction
  • cron: Triggered on a schedule
  • hunting_engine: Triggered by pattern detection from Hunting Engine

Description: Specifies how this workflow is triggered.

trigger (required)

Type: object

interface Trigger {
  type: string;
  source: string;
  condition: string;
  input_schema: Record<string, string>;
}
Enter fullscreen mode Exit fullscreen mode

Fields:

trigger.type

The specific event type that triggers this workflow.

For google_form entry point:

  • on_form_submit

For webdocket entry point:

  • on_docket_created
  • on_docket_updated
  • on_status_changed

For chatbot entry point:

  • on_message
  • on_intent

For cron entry point:

  • on_schedule

For hunting_engine entry point:

  • on_pattern_detected

trigger.source

The source system generating the event.

Allowed Values:

  • google_form
  • webdocket
  • gmail
  • chatbot
  • cron
  • hunting_engine

trigger.condition

A boolean expression that must evaluate to true for the workflow to execute.

Examples:

  • form_id == 'finance_invoice_intake'
  • new_status == 'completed'
  • intent == 'create_meeting_notes' AND has_meeting_details == true
  • schedule == '0 9 * * 1' (cron expression: Every Monday at 9am)

trigger.input_schema

Defines the expected structure of the trigger payload.

Format: Map of field names to type descriptions

Example:

{
  "input_schema": {
    "vendor_name": "string",
    "vendor_email": "string",
    "invoice_number": "string",
    "amount": "number",
    "due_date": "string (ISO 8601 date)",
    "attachment_url": "string (URL)"
  }
}
Enter fullscreen mode Exit fullscreen mode

steps (required)

Type: array

Min Items: 1

interface Step {
  id: string;
  service: string;
  action: string;
  inputs: Record<string, any>;
  outputs?: Record<string, string>;
  binary_logic: BinaryLogic;
  description?: string;
}
Enter fullscreen mode Exit fullscreen mode

step.id (required)

Type: string

Format: step_N where N is a number or descriptive identifier

Pattern: ^step_[a-zA-Z0-9_]+$

Must be unique within the workflow.

Examples:

  • step_1
  • step_validate
  • step_error_handler

step.service (required)

Type: enum

Allowed Values:

  • gmail
  • google_docs
  • google_forms
  • webdocket
  • google_sheets (future)
  • slack (future)

step.action (required)

Type: string

The action to perform on the service. See "Allowed Actions per Service" section below.

step.inputs (required)

Type: object

Inputs for the action. Structure depends on the service and action. Can contain template references.

step.outputs (optional)

Type: object

Describes the expected output structure. Used for documentation and validation.

Example:

{
  "outputs": {
    "doc_id": "string",
    "doc_url": "string (URL)"
  }
}
Enter fullscreen mode Exit fullscreen mode

step.binary_logic (required)

interface BinaryLogic {
  should_run_expr: string;
  on_success?: string;
  on_failure?: string;
  log_to_ledger?: boolean;
}
Enter fullscreen mode Exit fullscreen mode

binary_logic.should_run_expr (required)

Type: string

Expression that evaluates to 1/true (run) or 0/false (skip).

Examples:

  • "1" — Always run
  • "0" — Never run (disabled)
  • "[trigger.is](http://trigger.is)_urgent" — Run if trigger field is truthy
  • "step_[1.outputs.is](http://1.outputs.is)_valid" — Run if previous step output is valid
  • "trigger.amount > 5000" — Run if amount exceeds threshold
  • "step_[1.outputs.is](http://1.outputs.is)_valid && trigger.priority == 'high'" — Complex condition

binary_logic.on_success (optional, default: proceed to next step)

Type: string

Allowed Values:

  • "proceed to step_N" — Continue to specific step
  • "jump to step_N" — Skip to specific step
  • "halt workflow" — Stop execution (success)
  • "trigger workflow <name>" — Start another workflow

binary_logic.on_failure (optional, default: halt workflow)

Type: string

Allowed Values:

  • "halt workflow" — Stop execution (failure)
  • "log error and continue" — Continue despite error
  • "jump to step_N" — Skip to error handler
  • "trigger workflow <name>" — Start error handling workflow

binary_logic.log_to_ledger (optional, default: false)

Type: boolean

If true, forces a ledger entry for this step regardless of global gmail_ledger.log_events configuration.

gmail_ledger (optional)

interface GmailLedger {
  enabled: boolean;
  ledger_recipient: string;
  subject_template?: string;
  body_template?: string;
  log_events?: string[];
  labels?: string[];
}
Enter fullscreen mode Exit fullscreen mode

gmail_ledger.enabled (required if gmail_ledger provided)

Type: boolean

Default: true

Whether to write ledger emails for this workflow.

gmail_ledger.ledger_recipient (required if enabled)

Type: string (email address)

Email address to receive ledger entries.

Examples:

gmail_ledger.subject_template (optional)

Type: string

Custom subject line template. If not provided, uses default format.

Default: [LEDGER] workflow={workflow_name} event={event_type} cid={correlation_id}

gmail_ledger.body_template (optional)

Type: string

Custom body template. If not provided, uses default structured format.

gmail_ledger.log_events (optional)

Type: array

Default: [\"workflow_triggered\", \"step_completed\", \"workflow_completed\", \"error\"]

Allowed Values:

  • workflow_created
  • workflow_triggered
  • step_completed
  • step_skipped
  • validation_failed
  • error
  • workflow_completed
  • workflow_failed

gmail_ledger.labels (optional)

Type: array

Gmail labels to apply to ledger emails.

Example:

{
  \"labels\": [
    \"MORCO/Ledger\",
    \"MORCO/Workflows/Invoice-Intake\",
    \"Finance\"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Allowed Service Types and Actions

Service: gmail

Actions:

1. send_email

Required Inputs:

  • to: string (email address)
  • subject: string
  • body: string

Optional Inputs:

  • from: string (defaults to configured sender)
  • cc: string or array
  • bcc: string or array
  • attachments: array (file URLs or IDs)
  • headers: object (custom headers)

Outputs:

  • message_id: string
  • thread_id: string
  • sent_at: string (ISO 8601 timestamp)

2. create_draft

Required Inputs:

  • to: string
  • subject: string
  • body: string

Outputs:

  • draft_id: string
  • message_id: string

3. add_label

Required Inputs:

  • message_id: string
  • label: string

Outputs:

  • success: boolean

Service: google_docs

Actions:

1. create_doc_from_template

Required Inputs:

  • template_doc_id: string
  • content_blocks: array

Optional Inputs:

  • title: string
  • folder_id: string (Drive folder)

Outputs:

  • doc_id: string
  • doc_url: string

2. append_section

Required Inputs:

  • target_doc_id: string
  • content: string

Optional Inputs:

  • position: number (default: end of document)

Outputs:

  • doc_id: string
  • doc_url: string

3. overwrite_content

Required Inputs:

  • target_doc_id: string
  • content: string

Outputs:

  • doc_id: string
  • doc_url: string

Service: google_forms

Actions:

1. validate_submission

Required Inputs:

  • submission: object (form data)
  • required_fields: array

Optional Inputs:

  • numeric_fields: array
  • email_fields: array
  • date_fields: array

Outputs:

  • is_valid: boolean
  • validation_errors: array
  • normalized_payload: object

2. get_response

Required Inputs:

  • form_id: string
  • response_id: string

Outputs:

  • response: object

3. update_response

Required Inputs:

  • form_id: string
  • response_id: string
  • updates: object

Outputs:

  • success: boolean

Service: webdocket

Actions:

1. create_docket

Required Inputs:

  • title: string
  • description: string

Optional Inputs:

  • status: string
  • priority: string
  • assignee_email: string
  • due_date: string (ISO 8601)
  • custom_fields: object

Outputs:

  • docket_id: string
  • docket_url: string
  • created_at: string

2. update_docket

Required Inputs:

  • docket_id: string
  • updates: object

Outputs:

  • docket_id: string
  • docket_url: string
  • updated_at: string

3. get_docket_details

Required Inputs:

  • docket_id: string

Outputs:

  • docket: object (full docket data)

4. change_status

Required Inputs:

  • docket_id: string
  • new_status: string

Optional Inputs:

  • notes: string

Outputs:

  • docket_id: string
  • old_status: string
  • new_status: string
  • changed_at: string

Template Variable Rules

Reference Syntax

Trigger Data:

trigger.field_name
trigger.nested.field_name
trigger.array_field[0]
Enter fullscreen mode Exit fullscreen mode

Previous Step Outputs:

step_N.outputs.field_name
step_N.outputs.nested.field_name
step_N.status
Enter fullscreen mode Exit fullscreen mode

Step Status:

step_N.status → "success" | "failed" | "skipped"
Enter fullscreen mode Exit fullscreen mode

String Interpolation

Use variable syntax for embedding values in strings:

{
  \"subject\": \"Invoice trigger.invoice_number from trigger.vendor_name\"
}
Enter fullscreen mode Exit fullscreen mode

Direct Reference

Use direct reference when the entire value should be replaced:

{
  \"doc_url\": \"step_2.outputs.doc_url\"
}
Enter fullscreen mode Exit fullscreen mode

Allowed in:

  • step.inputs (all fields)
  • binary_logic.should_run_expr (boolean expressions)
  • gmail_ledger.subject_template (string interpolation)
  • gmail_ledger.body_template (string interpolation)

Not Allowed in:

  • workflow_name
  • description
  • step.id
  • step.service
  • step.action
  • binary_logic.on_success
  • binary_logic.on_failure

Validation Rules

All workflows must pass these validation checks before execution:

Schema Validation

  1. Required Fields: All required fields must be present
  2. Type Checking: All fields must match their specified types
  3. Enum Validation: Enum fields must use allowed values only
  4. Format Validation: String formats (email, URL, ISO dates) must be valid

Semantic Validation

  1. Unique Step IDs: No duplicate step.id values
  2. Valid Step References: All step_N references must point to existing steps
  3. Forward References Only: Steps can only reference previous steps (step_1 can't reference step_2)
  4. Template Variables: All template references must be valid
  5. Service/Action Pairs: Action must be supported by the specified service
  6. Required Inputs: All required inputs for the action must be provided

Logical Validation

  1. Reachable Steps: All steps must be reachable from workflow start
  2. No Circular Jumps: jump to logic must not create infinite loops
  3. Binary Logic: should_run_expr must be a valid boolean expression
  4. on_success/on_failure: Target steps must exist if using jump to or trigger workflow

Complete Workflow Example

{
  \"workflow_name\": \"invoice-intake-and-validation\",
  \"description\": \"Triggered when a vendor submits an invoice through the finance invoice form. Validates required fields, creates a structured Google Doc invoice record, creates a WebDocket entry for tracking, notifies the finance team, and logs all key events to the Gmail ledger.\",
  \"version\": \"1.0.0\",
  \"author\": \"Finance Team\",
  \"tags\": [\"finance\", \"invoices\", \"intake\"],

  \"entry_point\": \"google_form\",

  \"trigger\": {
    \"type\": \"on_form_submit\",
    \"source\": \"google_form\",
    \"condition\": \"form_id == 'finance_invoice_intake'\",
    \"input_schema\": {
      \"vendor_name\": \"string\",
      \"vendor_email\": \"string\",
      \"invoice_number\": \"string\",
      \"amount\": \"number\",
      \"due_date\": \"string (ISO 8601 date)\",
      \"attachment_url\": \"string (URL)\"
    }
  },

  \"steps\": [
    {
      \"id\": \"step_1\",
      \"description\": \"Validate invoice submission data\",
      \"service\": \"google_forms\",
      \"action\": \"validate_submission\",
      \"inputs\": {
        \"submission\": \"trigger\",
        \"required_fields\": [
          \"vendor_name\",
          \"vendor_email\",
          \"invoice_number\",
          \"amount\",
          \"due_date\"
        ],
        \"numeric_fields\": [\"amount\"],
        \"email_fields\": [\"vendor_email\"]
      },
      \"outputs\": {
        \"is_valid\": \"boolean\",
        \"validation_errors\": \"array\",
        \"normalized_payload\": \"object\"
      },
      \"binary_logic\": {
        \"should_run_expr\": \"1\",
        \"on_success\": \"proceed to step_2\",
        \"on_failure\": \"jump to step_error\",
        \"log_to_ledger\": true
      }
    },
    {
      \"id\": \"step_2\",
      \"description\": \"Create Google Doc invoice record from template\",
      \"service\": \"google_docs\",
      \"action\": \"create_doc_from_template\",
      \"inputs\": {
        \"template_doc_id\": \"1ABC123DEF456\",
        \"content_blocks\": [
          {
            \"type\": \"heading\",
            \"value\": \"Invoice: trigger.invoice_number\"
          },
          {
            \"type\": \"paragraph\",
            \"value\": \"Vendor: trigger.vendor_name\"
          },
          {
            \"type\": \"paragraph\",
            \"value\": \"Amount: $trigger.amount\"
          },
          {
            \"type\": \"paragraph\",
            \"value\": \"Due Date: trigger.due_date\"
          }
        ]
      },
      \"outputs\": {
        \"doc_id\": \"string\",
        \"doc_url\": \"string\"
      },
      \"binary_logic\": {
        \"should_run_expr\": \"step_
[1.outputs.is](http://1.outputs.is)_valid\",
        \"on_success\": \"proceed to step_3\",
        \"on_failure\": \"halt workflow\",
        \"log_to_ledger\": true
      }
    },
    {
      \"id\": \"step_3\",
      \"description\": \"Create WebDocket tracking entry\",
      \"service\": \"webdocket\",
      \"action\": \"create_docket\",
      \"inputs\": {
        \"title\": \"Invoice: trigger.invoice_number\",
        \"description\": \"Invoice from trigger.vendor_name for $trigger.amount. Due: trigger.due_date. Doc: step_2.outputs.doc_url\",
        \"status\": \"pending_review\",
        \"priority\": \"normal\",
        \"assignee_email\": \"[finance-team@company.com](mailto:finance-team@company.com)\",
        \"custom_fields\": {
          \"invoice_number\": \"trigger.invoice_number\",
          \"vendor_name\": \"trigger.vendor_name\",
          \"amount\": \"trigger.amount\",
          \"doc_url\": \"step_2.outputs.doc_url\"
        }
      },
      \"outputs\": {
        \"docket_id\": \"string\",
        \"docket_url\": \"string\"
      },
      \"binary_logic\": {
        \"should_run_expr\": \"1\",
        \"on_success\": \"proceed to step_4\",
        \"on_failure\": \"log error and continue\",
        \"log_to_ledger\": true
      }
    },
    {
      \"id\": \"step_4\",
      \"description\": \"Send notification email to finance team\",
      \"service\": \"gmail\",
      \"action\": \"send_email\",
      \"inputs\": {
        \"to\": \"[finance-team@company.com](mailto:finance-team@company.com)\",
        \"subject\": \"New Invoice: trigger.invoice_number from trigger.vendor_name\",
        \"body\": \"A new invoice has been received:\\n\\nVendor: trigger.vendor_name\\nInvoice Number: trigger.invoice_number\\nAmount: $trigger.amount\\nDue Date: trigger.due_date\\n\\nDocument: step_2.outputs.doc_url\\nDocket: step_3.outputs.docket_url\"
      },
      \"outputs\": {
        \"message_id\": \"string\"
      },
      \"binary_logic\": {
        \"should_run_expr\": \"1\",
        \"on_failure\": \"log error and continue\",
        \"log_to_ledger\": true
      }
    },
    {
      \"id\": \"step_error\",
      \"description\": \"Handle validation failure\",
      \"service\": \"gmail\",
      \"action\": \"send_email\",
      \"inputs\": {
        \"to\": \"trigger.vendor_email\",
        \"cc\": \"[finance-team@company.com](mailto:finance-team@company.com)\",
        \"subject\": \"Invoice Submission Error: trigger.invoice_number\",
        \"body\": \"Your invoice submission has validation errors:\\n\\nstep_1.outputs.validation_errors\\n\\nPlease correct these issues and resubmit.\"
      },
      \"binary_logic\": {
        \"should_run_expr\": \"!step_[1.outputs.is](http://1.outputs.is)_valid\",
        \"on_success\": \"halt workflow\",
        \"log_to_ledger\": true
      }
    }
  ],

  \"gmail_ledger\": {
    \"enabled\": true,
    \"ledger_recipient\": \"[ledger+finance@company.com](mailto:ledger+finance@company.com)\",
    \"log_events\": [
      \"workflow_triggered\",
      \"step_completed\",
      \"validation_failed\",
      \"error\",
      \"workflow_completed\",
      \"workflow_failed\"
    ],
    \"labels\": [
      \"MORCO/Ledger\",
      \"MORCO/Workflows/Invoice-Intake\",
      \"Finance/Invoices\"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

PROMPT 6 — Example Workflows (3 Full Examples)

This section provides three complete, production-ready workflow examples demonstrating different entry points and use cases.

Example 1: Invoice Intake & Validation

Use Case

Scenario: A vendor submits an invoice through a Google Form. The workflow validates the submission, creates a structured document, creates a tracking docket, and notifies the finance team.

Entry Point: google_form

Complexity: Medium (4 steps + error handler)

Services Used: Google Forms, Google Docs, WebDocket, Gmail

Visual Flow

┌─────────────────────────────────────────────────────────────────┐
│                      INVOICE INTAKE WORKFLOW                     │
└─────────────────────────────────────────────────────────────────┘

                    ┌──────────────────────┐
                    │  GOOGLE FORM SUBMIT  │
                    │  • Vendor Name       │
                    │  • Invoice Number    │
                    │  • Amount            │
                    │  • Due Date          │
                    └──────────┬───────────┘
                               │
                               ▼
                    ┌──────────────────────┐
                    │  STEP 1: VALIDATE    │
                    │  • Required fields   │
                    │  • Numeric formats   │
                    │  • Email validation  │
                    └──────────┬───────────┘
                               │
                ┌──────────────┼──────────────┐
                │ Valid?       │              │
                ▼              ▼              │
             YES              NO              │
                │              │              │
                │              ▼              │
                │   ┌──────────────────────┐ │
                │   │  STEP_ERROR:         │ │
                │   │  Send rejection      │ │
                │   │  email to vendor     │ │
                │   └──────────────────────┘ │
                │              │              │
                │              ▼              │
                │          HALT WORKFLOW     │
                │                            │
                ▼                            │
     ┌──────────────────────┐               │
     │  STEP 2: CREATE DOC  │               │
     │  • Use template      │               │
     │  • Fill invoice data │               │
     └──────────┬───────────┘               │
                │                            │
                ▼                            │
     ┌──────────────────────┐               │
     │  STEP 3: CREATE      │               │
     │  WEBDOCKET           │               │
     │  • Link to doc       │               │
     │  • Assign to team    │               │
     └──────────┬───────────┘               │
                │                            │
                ▼                            │
     ┌──────────────────────┐               │
     │  STEP 4: NOTIFY      │               │
     │  FINANCE TEAM        │               │
     │  • Doc link          │               │
     │  • Docket link       │               │
     └──────────┬───────────┘               │
                │                            │
                ▼                            │
           COMPLETED                         │
                                             │
┌────────────────────────────────────────────┴──────────────────┐
│  GMAIL LEDGER: 5-6 emails tracking entire workflow execution │
└───────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Complete JSON

{
  "workflow_name": "invoice-intake-and-validation",
  "description": "Validates vendor invoice submissions, creates documentation, tracks in WebDocket, and notifies finance team. Handles both successful and failed validations with appropriate routing.",
  "version": "1.0.0",
  "author": "Finance Automation Team",
  "tags": ["finance", "invoices", "validation", "intake"],

  "entry_point": "google_form",

  "trigger": {
    "type": "on_form_submit",
    "source": "google_form",
    "condition": "form_id == 'finance_invoice_intake'",
    "input_schema": {
      "vendor_name": "string",
      "vendor_email": "string (email)",
      "invoice_number": "string",
      "amount": "number",
      "due_date": "string (ISO 8601 date)",
      "attachment_url": "string (URL)",
      "notes": "string (optional)"
    }
  },

  "steps": [
    {
      "id": "step_1",
      "description": "Validate invoice submission data for completeness and correctness",
      "service": "google_forms",
      "action": "validate_submission",
      "inputs": {
        "submission": "trigger",
        "required_fields": [
          "vendor_name",
          "vendor_email",
          "invoice_number",
          "amount",
          "due_date"
        ],
        "numeric_fields": ["amount"],
        "email_fields": ["vendor_email"]
      },
      "outputs": {
        "is_valid": "boolean",
        "validation_errors": "array<string>",
        "normalized_payload": "object"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed to step_2",
        "on_failure": "jump to step_error",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_2",
      "description": "Create structured Google Doc from template with invoice details",
      "service": "google_docs",
      "action": "create_doc_from_template",
      "inputs": {
        "template_doc_id": "1ABC123DEF456GHI789JKL",
        "title": "Invoice: trigger.invoice_number - trigger.vendor_name",
        "content_blocks": [
          {
            "type": "heading",
            "value": "Invoice Record: trigger.invoice_number"
          },
          {
            "type": "paragraph",
            "value": "Submission Date: trigger.submission_timestamp"
          },
          {
            "type": "heading",
            "value": "Vendor Information"
          },
          {
            "type": "paragraph",
            "value": "Name: trigger.vendor_name"
          },
          {
            "type": "paragraph",
            "value": "Email: trigger.vendor_email"
          },
          {
            "type": "heading",
            "value": "Invoice Details"
          },
          {
            "type": "paragraph",
            "value": "Invoice Number: trigger.invoice_number"
          },
          {
            "type": "paragraph",
            "value": "Amount: $trigger.amount"
          },
          {
            "type": "paragraph",
            "value": "Due Date: trigger.due_date"
          },
          {
            "type": "paragraph",
            "value": "Attachment: trigger.attachment_url"
          },
          {
            "type": "heading",
            "value": "Notes"
          },
          {
            "type": "paragraph",
            "value": "trigger.notes"
          }
        ]
      },
      "outputs": {
        "doc_id": "string",
        "doc_url": "string"
      },
      "binary_logic": {
        "should_run_expr": "step_[1.outputs.is](http://1.outputs.is)_valid",
        "on_success": "proceed to step_3",
        "on_failure": "halt workflow",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_3",
      "description": "Create WebDocket for finance team review and tracking",
      "service": "webdocket",
      "action": "create_docket",
      "inputs": {
        "title": "Invoice Review: trigger.invoice_number",
        "description": "Vendor: trigger.vendor_name\\nAmount: $trigger.amount\\nDue: trigger.due_date\\n\\nDocument: step_2.outputs.doc_url\\n\\nSubmitted: trigger.submission_timestamp",
        "status": "pending_review",
        "priority": "normal",
        "assignee_email": "[finance-team@company.com](mailto:finance-team@company.com)",
        "due_date": "trigger.due_date",
        "custom_fields": {
          "invoice_number": "trigger.invoice_number",
          "vendor_name": "trigger.vendor_name",
          "amount": "trigger.amount",
          "vendor_email": "trigger.vendor_email",
          "doc_url": "step_2.outputs.doc_url",
          "correlation_id": "run_state.correlation_id"
        }
      },
      "outputs": {
        "docket_id": "string",
        "docket_url": "string",
        "created_at": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed to step_4",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_4",
      "description": "Send notification to finance team with all relevant links",
      "service": "gmail",
      "action": "send_email",
      "inputs": {
        "to": "[finance-team@company.com](mailto:finance-team@company.com)",
        "subject": "New Invoice Submission: trigger.invoice_number - trigger.vendor_name",
        "body": "A new invoice has been received and validated.\\n\\n=== VENDOR ===\\nName: trigger.vendor_name\\nEmail: trigger.vendor_email\\n\\n=== INVOICE ===\\nInvoice Number: trigger.invoice_number\\nAmount: $trigger.amount\\nDue Date: trigger.due_date\\n\\n=== DOCUMENTS ===\\nInvoice Document: step_2.outputs.doc_url\\nTracking Docket: step_3.outputs.docket_url\\nOriginal Attachment: trigger.attachment_url\\n\\n=== NEXT STEPS ===\\nPlease review the invoice in the docket and take appropriate action.\\n\\nCorrelation ID: run_state.correlation_id"
      },
      "outputs": {
        "message_id": "string",
        "sent_at": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_error",
      "description": "Handle validation failure by notifying vendor of errors",
      "service": "gmail",
      "action": "send_email",
      "inputs": {
        "to": "trigger.vendor_email",
        "cc": "[finance-team@company.com](mailto:finance-team@company.com)",
        "subject": "Invoice Submission Error: trigger.invoice_number",
        "body": "Hello trigger.vendor_name,\\n\\nYour invoice submission (trigger.invoice_number) could not be processed due to the following validation errors:\\n\\nstep_1.outputs.validation_errors\\n\\nPlease correct these issues and resubmit the invoice through the same form.\\n\\nIf you have questions, please contact [finance-team@company.com](mailto:finance-team@company.com).\\n\\nThank you,\\nFinance Automation System"
      },
      "outputs": {
        "message_id": "string"
      },
      "binary_logic": {
        "should_run_expr": "!step_[1.outputs.is](http://1.outputs.is)_valid",
        "on_success": "halt workflow",
        "on_failure": "halt workflow",
        "log_to_ledger": true
      }
    }
  ],

  "gmail_ledger": {
    "enabled": true,
    "ledger_recipient": "[ledger+finance@company.com](mailto:ledger+finance@company.com)",
    "log_events": [
      "workflow_triggered",
      "step_completed",
      "validation_failed",
      "error",
      "workflow_completed",
      "workflow_failed"
    ],
    "labels": [
      "MORCO/Ledger",
      "MORCO/Workflows/Invoice-Intake",
      "MORCO/Department/Finance"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Logic Explanation

Trigger Phase:

  • Workflow activates when the finance invoice intake form (form_id == 'finance_invoice_intake') is submitted
  • Captures vendor information, invoice details, and optional notes

Validation Logic (Step 1):

  • Checks all required fields are present
  • Validates amount is numeric
  • Validates vendor_email is a valid email format
  • If validation fails: jumps to step_error, bypassing all processing steps
  • If validation succeeds: continues to step_2

Document Creation (Step 2):

  • Only runs if step_[1.outputs.is](http://1.outputs.is)_valid == true (explicit conditional)
  • Creates a Google Doc from a predefined template
  • Populates template with structured invoice data
  • Output: doc_id and doc_url for reference in subsequent steps

Docket Creation (Step 3):

  • Creates a WebDocket task for finance team tracking
  • Links to the Google Doc created in Step 2
  • Includes correlation ID for cross-system tracing
  • Uses log error and continue strategy - if WebDocket fails, workflow continues
  • Priority: normal (could be made dynamic based on amount)

Team Notification (Step 4):

  • Sends comprehensive email to finance team
  • Includes all relevant links (doc, docket, attachment)
  • Provides correlation ID for ledger queries
  • Uses log error and continue - even if email fails, workflow is marked complete

Error Handling (step_error):

  • Only runs if !step_[1.outputs.is](http://1.outputs.is)_valid (validation failed)
  • Sends rejection email to vendor with specific error details
  • CCs finance team for visibility
  • Halts workflow after sending (no further processing needed)

Ledger Integration:

  • Logs 5-6 events per successful run
  • Logs 2-3 events per failed validation
  • All events queryable by correlation ID
  • Enables complete audit trail

Example 2: Chatbot Request → Case Creation

Use Case

Scenario: A user interacts with a chatbot to request support. The chatbot extracts structured data from the conversation, then triggers this workflow to create a formal case, generate documentation, and send confirmations.

Entry Point: chatbot

Complexity: Medium (4 steps)

Services Used: WebDocket, Google Docs, Gmail

Visual Flow

┌─────────────────────────────────────────────────────────────────┐
│                  CHATBOT CASE CREATION WORKFLOW                  │
└─────────────────────────────────────────────────────────────────┘

        ┌──────────────────────────────────────┐
        │  CHATBOT CONVERSATION                │
        │  User: "I need help with..."         │
        │  Bot: Extracts structured data       │
        │  Intent: create_support_case         │
        └──────────────┬───────────────────────┘
                       │
                       ▼
        ┌──────────────────────────────────────┐
        │  WORKFLOW TRIGGERED                  │
        │  • User name & email                 │
        │  • Issue description                 │
        │  • Priority                          │
        │  • Conversation transcript           │
        └──────────────┬───────────────────────┘
                       │
                       ▼
        ┌──────────────────────────────────────┐
        │  STEP 1: CREATE WEBDOCKET CASE       │
        │  • Title from issue summary          │
        │  • Description with transcript       │
        │  • Auto-assign to support team       │
        └──────────────┬───────────────────────┘
                       │
                       ▼
        ┌──────────────────────────────────────┐
        │  STEP 2: GENERATE CASE DOC           │
        │  • Formal case documentation         │
        │  • Full conversation log             │
        │  • Action items extracted            │
        └──────────────┬───────────────────────┘
                       │
                       ▼
        ┌──────────────────────────────────────┐
        │  STEP 3: UPDATE DOCKET               │
        │  • Add doc link to docket            │
        │  • Add correlation ID                │
        └──────────────┬───────────────────────┘
                       │
                       ▼
        ┌──────────────────────────────────────┐
        │  STEP 4: SEND CONFIRMATION           │
        │  • Email to user                     │
        │  • Case number & links               │
        │  • Expected response time            │
        └──────────────┬───────────────────────┘
                       │
                       ▼
                  COMPLETED

┌───────────────────────────────────────────────────────────────┐
│  GMAIL LEDGER: Complete workflow trace with all case details │
└───────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Complete JSON

{
  "workflow_name": "chatbot-support-case-creation",
  "description": "Triggered when chatbot detects a support request intent. Creates a WebDocket case, generates formal documentation, and sends confirmation to the user. Designed for conversational support intake with full transcript preservation.",
  "version": "1.0.0",
  "author": "Support Automation Team",
  "tags": ["support", "chatbot", "cases", "customer-service"],

  "entry_point": "chatbot",

  "trigger": {
    "type": "on_intent",
    "source": "chatbot",
    "condition": "intent == 'create_support_case' AND has_required_data == true",
    "input_schema": {
      "user_name": "string",
      "user_email": "string (email)",
      "issue_summary": "string (max 200 chars)",
      "issue_description": "string",
      "priority": "string (low|normal|high|urgent)",
      "conversation_id": "string",
      "conversation_transcript": "string",
      "extracted_action_items": "array<string> (optional)",
      "request_timestamp": "string (ISO 8601)"
    }
  },

  "steps": [
    {
      "id": "step_1",
      "description": "Create WebDocket support case from chatbot interaction",
      "service": "webdocket",
      "action": "create_docket",
      "inputs": {
        "title": "Support Case: trigger.issue_summary",
        "description": "User: trigger.user_name (trigger.user_email)\\n\\nIssue:\\ntrigger.issue_description\\n\\nPriority: trigger.priority\\nConversation ID: trigger.conversation_id\\n\\nRequested: trigger.request_timestamp",
        "status": "new",
        "priority": "trigger.priority",
        "assignee_email": "[support-team@company.com](mailto:support-team@company.com)",
        "custom_fields": {
          "source": "chatbot",
          "user_name": "trigger.user_name",
          "user_email": "trigger.user_email",
          "conversation_id": "trigger.conversation_id",
          "created_via": "chatbot-automation"
        }
      },
      "outputs": {
        "docket_id": "string",
        "docket_url": "string",
        "case_number": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed to step_2",
        "on_failure": "halt workflow",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_2",
      "description": "Generate formal case documentation with full conversation history",
      "service": "google_docs",
      "action": "create_doc_from_template",
      "inputs": {
        "template_doc_id": "1SUPPORT987CASE654TEMPLATE321",
        "title": "Case trigger.issue_summary - trigger.user_name",
        "content_blocks": [
          {
            "type": "heading",
            "value": "Support Case: step_[1.outputs.case](http://1.outputs.case)_number"
          },
          {
            "type": "paragraph",
            "value": "Created: trigger.request_timestamp"
          },
          {
            "type": "paragraph",
            "value": "Source: Chatbot (Conversation ID: trigger.conversation_id)"
          },
          {
            "type": "heading",
            "value": "User Information"
          },
          {
            "type": "paragraph",
            "value": "Name: trigger.user_name"
          },
          {
            "type": "paragraph",
            "value": "Email: trigger.user_email"
          },
          {
            "type": "heading",
            "value": "Issue Summary"
          },
          {
            "type": "paragraph",
            "value": "trigger.issue_summary"
          },
          {
            "type": "heading",
            "value": "Detailed Description"
          },
          {
            "type": "paragraph",
            "value": "trigger.issue_description"
          },
          {
            "type": "heading",
            "value": "Priority"
          },
          {
            "type": "paragraph",
            "value": "trigger.priority"
          },
          {
            "type": "heading",
            "value": "Action Items"
          },
          {
            "type": "paragraph",
            "value": "trigger.extracted_action_items"
          },
          {
            "type": "heading",
            "value": "Full Conversation Transcript"
          },
          {
            "type": "paragraph",
            "value": "trigger.conversation_transcript"
          },
          {
            "type": "heading",
            "value": "Tracking"
          },
          {
            "type": "paragraph",
            "value": "Docket: step_1.outputs.docket_url"
          },
          {
            "type": "paragraph",
            "value": "Correlation ID: run_state.correlation_id"
          }
        ]
      },
      "outputs": {
        "doc_id": "string",
        "doc_url": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed to step_3",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_3",
      "description": "Update WebDocket with link to case documentation",
      "service": "webdocket",
      "action": "update_docket",
      "inputs": {
        "docket_id": "step_1.outputs.docket_id",
        "updates": {
          "custom_fields": {
            "case_doc_url": "step_2.outputs.doc_url",
            "correlation_id": "run_state.correlation_id",
            "doc_created_at": "step_2.outputs.created_at"
          }
        }
      },
      "outputs": {
        "updated_at": "string"
      },
      "binary_logic": {
        "should_run_expr": "step_2.outputs.doc_id != null",
        "on_success": "proceed to step_4",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_4",
      "description": "Send confirmation email to user with case details",
      "service": "gmail",
      "action": "send_email",
      "inputs": {
        "to": "trigger.user_email",
        "subject": "Your Support Case Has Been Created - step_[1.outputs.case](http://1.outputs.case)_number",
        "body": "Hello trigger.user_name,\\n\\nThank you for contacting support. Your case has been created and assigned to our team.\\n\\n=== CASE DETAILS ===\\nCase Number: step_[1.outputs.case](http://1.outputs.case)_number\\nPriority: trigger.priority\\nStatus: New\\n\\n=== WHAT YOU REPORTED ===\\ntrigger.issue_summary\\n\\n=== WHAT HAPPENS NEXT ===\\nOur support team will review your case and respond within:\\n- Urgent: 2 hours\\n- High: 4 hours\\n- Normal: 1 business day\\n- Low: 2 business days\\n\\n=== CASE TRACKING ===\\nYou can track your case here: step_1.outputs.docket_url\\nCase Documentation: step_2.outputs.doc_url\\n\\nCase Reference: step_[1.outputs.case](http://1.outputs.case)_number\\n\\nIf you have additional information, please reply to this email.\\n\\nBest regards,\\nSupport Team"
      },
      "outputs": {
        "message_id": "string",
        "sent_at": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    }
  ],

  "gmail_ledger": {
    "enabled": true,
    "ledger_recipient": "[ledger+support@company.com](mailto:ledger+support@company.com)",
    "log_events": [
      "workflow_triggered",
      "step_completed",
      "error",
      "workflow_completed",
      "workflow_failed"
    ],
    "labels": [
      "MORCO/Ledger",
      "MORCO/Workflows/Support-Case-Creation",
      "MORCO/Department/Support",
      "MORCO/Source/Chatbot"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Logic Explanation

Trigger Phase:

  • Workflow activates when chatbot detects intent == 'create_support_case'
  • Chatbot must extract and provide all required structured data
  • Conditional: has_required_data == true ensures data quality before triggering

Case Creation (Step 1):

  • Creates WebDocket immediately to capture the case
  • Uses chatbot-extracted priority level directly
  • Auto-assigns to support-team@company.com
  • Stores conversation ID for traceability
  • Critical step: failure halts workflow (support case MUST be created)

Documentation Generation (Step 2):

  • Creates comprehensive Google Doc with all case details
  • Preserves full conversation transcript (important for context)
  • Includes extracted action items if chatbot identified any
  • Embeds docket link for cross-reference
  • Non-critical: uses log error and continue - case exists even if doc fails

Docket Enhancement (Step 3):

  • Conditional: step_2.outputs.doc_id != null (only if doc was created)
  • Updates the WebDocket with doc URL
  • Adds correlation ID for distributed tracing
  • Allows failure - docket is already functional without doc link

User Confirmation (Step 4):

  • Sends professional confirmation email
  • Includes case number for future reference
  • Sets expectations for response time based on priority
  • Provides tracking links
  • Non-critical: case is created even if email fails

Workflow Characteristics:

  • Resilience: Only Step 1 is critical; others gracefully degrade
  • User Experience: Fast initial response (case created immediately)
  • Traceability: Conversation ID + correlation ID = full audit trail
  • Automation: No human intervention required from chatbot to case creation

Example 3: WebDocket Status Change Handler

Use Case

Scenario: When a WebDocket status changes to "completed", automatically update documentation, notify stakeholders, archive records, and log the completion for audit purposes.

Entry Point: webdocket

Complexity: Medium (5 steps with conditional logic)

Services Used: WebDocket, Google Docs, Gmail

Visual Flow

┌─────────────────────────────────────────────────────────────────┐
│              WEBDOCKET STATUS CHANGE HANDLER WORKFLOW            │
└─────────────────────────────────────────────────────────────────┘

          ┌──────────────────────────────────────┐
          │  WEBDOCKET STATUS CHANGED            │
          │  • Old Status: in_progress           │
          │  • New Status: completed             │
          │  • Completed By: [user@company.com](mailto:user@company.com)    │
          └──────────────┬───────────────────────┘
                         │
                         ▼
          ┌──────────────────────────────────────┐
          │  TRIGGER CONDITION CHECK             │
          │  new_status == 'completed'           │
          └──────────────┬───────────────────────┘
                         │ Match
                         ▼
          ┌──────────────────────────────────────┐
          │  STEP 1: GET DOCKET DETAILS          │
          │  • Fetch full docket data            │
          │  • Get assignee                      │
          │  • Get related doc URLs              │
          └──────────────┬───────────────────────┘
                         │
                         ▼
          ┌──────────────────────────────────────┐
          │  STEP 2: UPDATE CASE DOC             │
          │  • Append completion section         │
          │  • Add timestamp & user              │
          │  • Include resolution notes          │
          └──────────────┬───────────────────────┘
                         │
                         ▼
          ┌──────────────────────────────────────┐
          │  STEP 3: NOTIFY ASSIGNEE             │
          │  Should run: assignee exists?        │
          │  • Send completion confirmation      │
          │  • Include final status              │
          └──────────────┬───────────────────────┘
                         │
                         ▼
          ┌──────────────────────────────────────┐
          │  STEP 4: NOTIFY CUSTOMER             │
          │  Should run: customer email exists?  │
          │  • Send closure notification         │
          │  • Request feedback                  │
          └──────────────┬───────────────────────┘
                         │
                         ▼
          ┌──────────────────────────────────────┐
          │  STEP 5: CREATE ARCHIVE RECORD       │
          │  • Generate completion summary doc   │
          │  • Link all related docs             │
          │  • Mark for long-term storage        │
          └──────────────┬───────────────────────┘
                         │
                         ▼
                    COMPLETED

┌───────────────────────────────────────────────────────────────┐
│  GMAIL LEDGER: Full completion workflow with all updates     │
└───────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Complete JSON

{
  "workflow_name": "webdocket-completion-handler",
  "description": "Triggered when a WebDocket status changes to 'completed'. Updates documentation, notifies relevant parties (assignee and customer if applicable), and creates archival records. Demonstrates conditional notification logic based on available data.",
  "version": "1.0.0",
  "author": "Operations Automation Team",
  "tags": ["webdocket", "completion", "notifications", "archival"],

  "entry_point": "webdocket",

  "trigger": {
    "type": "on_status_changed",
    "source": "webdocket",
    "condition": "new_status == 'completed'",
    "input_schema": {
      "docket_id": "string",
      "title": "string",
      "old_status": "string",
      "new_status": "string (must be 'completed')",
      "completed_by": "string (email)",
      "completion_notes": "string",
      "completion_timestamp": "string (ISO 8601)",
      "assignee_email": "string (optional)",
      "metadata": "object (optional, may contain customer_email, case_doc_url)"
    }
  },

  "steps": [
    {
      "id": "step_1",
      "description": "Fetch complete docket details including all custom fields",
      "service": "webdocket",
      "action": "get_docket_details",
      "inputs": {
        "docket_id": "trigger.docket_id"
      },
      "outputs": {
        "docket": "object (full docket data)",
        "assignee_email": "string",
        "customer_email": "string",
        "case_doc_url": "string",
        "original_requester": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed to step_2",
        "on_failure": "halt workflow",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_2",
      "description": "Update case documentation with completion details",
      "service": "google_docs",
      "action": "append_section",
      "inputs": {
        "target_doc_id": "step_[1.outputs.case](http://1.outputs.case)_doc_url",
        "content": "\\n\\n=== CASE COMPLETION ===\\n\\nCompleted By: trigger.completed_by\\nCompletion Date: trigger.completion_timestamp\\nPrevious Status: trigger.old_status\\nFinal Status: [trigger.new](http://trigger.new)_status\\n\\n=== RESOLUTION NOTES ===\\n\\ntrigger.completion_notes\\n\\n=== AUDIT TRAIL ===\\n\\nCorrelation ID: run_state.correlation_id\\nWorkflow: webdocket-completion-handler\\nProcessed: run_state.timestamp"
      },
      "outputs": {
        "doc_id": "string",
        "updated_at": "string"
      },
      "binary_logic": {
        "should_run_expr": "step_[1.outputs.case](http://1.outputs.case)_doc_url != null",
        "on_success": "proceed to step_3",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_3",
      "description": "Notify assignee of docket completion",
      "service": "gmail",
      "action": "send_email",
      "inputs": {
        "to": "step_1.outputs.assignee_email",
        "subject": "Docket Completed: trigger.title",
        "body": "Hello,\\n\\nThe docket you were assigned has been marked as completed.\\n\\n=== DOCKET DETAILS ===\\nTitle: trigger.title\\nDocket ID: trigger.docket_id\\nCompleted By: trigger.completed_by\\nCompletion Time: trigger.completion_timestamp\\n\\n=== RESOLUTION ===\\ntrigger.completion_notes\\n\\n=== DOCUMENTATION ===\\nCase Document: step_[1.outputs.case](http://1.outputs.case)_doc_url\\nDocket URL: step_1.outputs.docket_url\\n\\nThank you for your work on this case.\\n\\nAutomated notification from MORCO"
      },
      "outputs": {
        "message_id": "string"
      },
      "binary_logic": {
        "should_run_expr": "step_1.outputs.assignee_email != null",
        "on_success": "proceed to step_4",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_4",
      "description": "Notify customer if customer email is available in docket metadata",
      "service": "gmail",
      "action": "send_email",
      "inputs": {
        "to": "step_1.outputs.customer_email",
        "subject": "Your Request Has Been Completed - trigger.title",
        "body": "Hello,\\n\\nWe're writing to let you know that your request has been completed.\\n\\n=== REQUEST SUMMARY ===\\ntrigger.title\\n\\nCompleted: trigger.completion_timestamp\\n\\n=== RESOLUTION ===\\ntrigger.completion_notes\\n\\n=== YOUR FEEDBACK ===\\nWe value your feedback. Please let us know how we did by replying to this email.\\n\\nIf you have any questions about this resolution, please don't hesitate to reach out.\\n\\nThank you,\\nOperations Team\\n\\n---\\nReference: trigger.docket_id"
      },
      "outputs": {
        "message_id": "string",
        "sent_to": "string"
      },
      "binary_logic": {
        "should_run_expr": "step_1.outputs.customer_email != null && step_1.outputs.customer_email != ''",
        "on_success": "proceed to step_5",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    },
    {
      "id": "step_5",
      "description": "Create archive record summarizing the completed docket",
      "service": "google_docs",
      "action": "create_doc_from_template",
      "inputs": {
        "template_doc_id": "1ARCHIVE987TEMPLATE654COMPLETE321",
        "title": "ARCHIVED - trigger.title - trigger.completion_timestamp",
        "folder_id": "archive_folder_id",
        "content_blocks": [
          {
            "type": "heading",
            "value": "Completion Archive: trigger.docket_id"
          },
          {
            "type": "paragraph",
            "value": "Original Title: trigger.title"
          },
          {
            "type": "paragraph",
            "value": "Completed: trigger.completion_timestamp"
          },
          {
            "type": "paragraph",
            "value": "Completed By: trigger.completed_by"
          },
          {
            "type": "heading",
            "value": "Status History"
          },
          {
            "type": "paragraph",
            "value": "Initial Status: (from docket history)"
          },
          {
            "type": "paragraph",
            "value": "Final Status: [trigger.new](http://trigger.new)_status"
          },
          {
            "type": "paragraph",
            "value": "Previous Status: trigger.old_status"
          },
          {
            "type": "heading",
            "value": "Resolution"
          },
          {
            "type": "paragraph",
            "value": "trigger.completion_notes"
          },
          {
            "type": "heading",
            "value": "Related Documents"
          },
          {
            "type": "paragraph",
            "value": "Case Documentation: step_[1.outputs.case](http://1.outputs.case)_doc_url"
          },
          {
            "type": "paragraph",
            "value": "Original Docket: step_1.outputs.docket_url"
          },
          {
            "type": "heading",
            "value": "Notifications Sent"
          },
          {
            "type": "paragraph",
            "value": "Assignee: step_1.outputs.assignee_email - step_3.outputs.message_id"
          },
          {
            "type": "paragraph",
            "value": "Customer: step_1.outputs.customer_email - step_4.outputs.message_id"
          },
          {
            "type": "heading",
            "value": "Audit Trail"
          },
          {
            "type": "paragraph",
            "value": "Workflow: webdocket-completion-handler"
          },
          {
            "type": "paragraph",
            "value": "Correlation ID: run_state.correlation_id"
          },
          {
            "type": "paragraph",
            "value": "Archived: run_state.timestamp"
          }
        ]
      },
      "outputs": {
        "archive_doc_id": "string",
        "archive_doc_url": "string"
      },
      "binary_logic": {
        "should_run_expr": "1",
        "on_success": "proceed",
        "on_failure": "log error and continue",
        "log_to_ledger": true
      }
    }
  },

  "gmail_ledger": {
    "enabled": true,
    "ledger_recipient": "[ledger+operations@company.com](mailto:ledger+operations@company.com)",
    "log_events": [
      "workflow_triggered",
      "step_completed",
      "step_skipped",
      "error",
      "workflow_completed",
      "workflow_failed"
    ],
    "labels": [
      "MORCO/Ledger",
      "MORCO/Workflows/Docket-Completion",
      "MORCO/Department/Operations",
      "MORCO/Trigger/WebDocket"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

Logic Explanation

Trigger Phase:

  • Workflow only activates when new_status == 'completed' (ignores other status changes)
  • Captures who completed the docket and when
  • Includes completion notes for context

Data Gathering (Step 1):

  • Critical first step: fetches complete docket details
  • Needed because trigger payload may not include all metadata
  • Retrieves assignee email, customer email (if exists), and doc URLs
  • Failure here halts workflow - can't proceed without data

Documentation Update (Step 2):

  • Conditional: step_[1.outputs.case](http://1.outputs.case)_doc_url != null
  • Only runs if a case doc exists (not all dockets have docs)
  • Appends completion section with timestamp, completer, and notes
  • Non-critical: uses log error and continue

Assignee Notification (Step 3):

  • Conditional: step_1.outputs.assignee_email != null
  • Only sends if docket had an assignee
  • Professional notification with full context
  • Includes all relevant links
  • Non-critical: docket is completed regardless of email success

Customer Notification (Step 4):

  • Conditional: step_1.outputs.customer_email != null && != ''
  • Two-part check: field exists AND is not empty string
  • Customer-facing language (different tone than assignee email)
  • Requests feedback
  • Non-critical: completion valid even without customer notification

Archival Record (Step 5):

  • Always runs (unconditional)
  • Creates comprehensive archive document
  • Consolidates all completion information in one place
  • Includes references to all emails sent (via message IDs)
  • Saved to designated archive folder
  • Non-critical: original docket and case doc still exist if this fails

Advanced Features Demonstrated:

  1. Multi-Condition Logic: Step 4 shows AND logic in should_run_expr
  2. Graceful Degradation: Each notification step can fail independently
  3. Data Enrichment: Step 1 enriches trigger data with full docket details
  4. Audit Completeness: Archive doc includes message IDs for sent emails
  5. Conditional Notifications: Different stakeholders get different messages

Ledger Benefits:

  • Logs both step_completed and step_skipped events
  • Can query ledger to see which notifications were actually sent
  • Correlation ID traces the entire completion process
  • Enables metrics: average time from creation to completion

Key Patterns Across Examples

Pattern 1: Progressive Robustness

Strategy: Critical steps use on_failure: halt workflow, while nice-to-have steps use log error and continue.

Example 1: Validation must succeed; notifications can fail

Example 2: Case creation must succeed; email can fail

Example 3: Data fetch must succeed; notifications can fail

Pattern 2: Conditional Execution

All examples use should_run_expr to handle optional data:

  • Example 1: Skip doc creation if validation fails
  • Example 2: Skip docket update if doc creation failed
  • Example 3: Skip customer notification if no customer email

Pattern 3: Data Flow Chains

Each example builds a data pipeline:

Trigger Data 
  → Step 1 validates/enriches 
  → Step 2 uses Step 1 outputs 
  → Step 3 uses Step 1 + Step 2 outputs
  → etc.
Enter fullscreen mode Exit fullscreen mode

Pattern 4: Correlation for Traceability

All examples:

  • Generate correlation ID at start
  • Include it in docket custom fields
  • Reference it in emails
  • Write it to documents
  • Log it in ledger

Pattern 5: User-Facing vs Internal Operations

Notice the tone difference:

  • Internal (Step 3 in Example 3): Technical, includes system details
  • User-Facing (Step 4 in Examples 1, 2, 3): Friendly, hides complexity

Top comments (0)