Migration Guide: Phase 3 → Phase 4+

Project path: /Users/chad/workspace/agent-skills/subagent-coordinator/ Version: 4.0.0

This guide helps you migrate from the Phase 3 monolithic exec-monitor to the Phase 4+ event-driven architecture with independent plugins.


1. Why Migrate?

1.1 Benefits of the New Architecture

Benefit Description
Loose Coupling Plugins operate independently; the Skill works without any plugins
Selective Installation Install only the plugins you need (e.g., just observability)
Independent Updates Update or replace plugins without touching the core Skill
Specialized Functionality Each plugin does one thing well
Testability Test each plugin in isolation
Fault Isolation A failure in one plugin doesn't crash the others

1.2 Phase 3 vs Phase 4+ Comparison

Aspect Phase 3 (Monolithic) Phase 4+ (Event-Driven)
Architecture Single exec-monitor module Skill + 3 independent plugins
Plugin Loading All-or-nothing Each plugin optional
Event System Internal function calls Standard event bus
Complexity Scoring Built into exec-monitor Dedicated service (observability or fallback)
Task Persistence exec-monitor only Dedicated Taskr plugin
Quality Gates exec-monitor only exec-monitor plugin (or fallback)
Metrics Basic logging Full telemetry with rate limiting
Tracing None subagent-observability plugin

2. Architecture Changes

2.1 What Changed from Phase 3

Before (Phase 3):


Main Agent
    │
    └──▶ exec-monitor (monolithic)
             ├── Complexity scoring
             ├── Quality gates
             ├── Checkpoints
             └── Retry logic

After (Phase 4+):


Main Agent
    │
    └──▶ subagent-coordinator (skill)
             │
             ├── Event Bus
             │
             ├──▶ subagent-observability (metrics, tracing)
             ├──▶ Taskr (persistence)
             └──▶ exec-monitor (quality gates)

    Note: All plugins are OPTIONAL.
    Built-in fallbacks handle everything when plugins are absent.

2.2 New Directory Structure


Phase 3:
subagent-coordinator/
└── exec-monitor/           # Single monolithic module
    └── src/

Phase 4+:
subagent-coordinator/
├── skill/
│   ├── SKILL.md            # Skill definition
│   ├── events.ts           # Event contract (shared)
│   └── references/         # Documentation and resources
├── plugins/
│   ├── exec-monitor/          # Quality gates plugin
│   ├── subagent-observability/ # Metrics & tracing plugin
│   └── taskr/                 # Persistence plugin


3. Plugin Migration

3.1 How to Port Old Hooks to New Plugins

Phase 3 Code (Old):

// Inside exec-monitor/src/index.ts
const hooks = {
  async beforeDelegation(task, complexity) {
    // Quality gate logic
    const result = runQualityGate(task);
    return result;
  },

  async afterExecution(task, result) {
    // Checkpoint logic
    saveCheckpoint(task, result);
    return { saved: true };
  },
};

Phase 4+ Code (New):

// Inside plugins/exec-monitor/src/hooks/before_delegation.ts
import type { BeforeDelegationEvent } from "../../../events";

export async function handleBeforeDelegation(
  event: BeforeDelegationEvent
) {
  const { task } = event;

  // Quality gate logic
  const result = runQualityGate(task);

  return {
    pass: result.pass,
    checks: result.checks,
  };
}

// Inside plugins/exec-monitor/src/index.ts
import { SUBAGENT_COORDINATOR_EVENTS } from "../../events";
import { handleBeforeDelegation } from "./hooks/before_delegation";

export default definePluginEntry({
  id: "subagent-exec-monitor",
  name: "Subagent Coordinator Execution Monitor",

  register(api) {
    api.registerHook(
      SUBAGENT_COORDINATOR_EVENTS.BEFORE_DELEGATION,
      handleBeforeDelegation
    );
  }
});

3.2 Porting Checklist

Phase 3 Component Phase 4+ Location Notes
beforeDelegation exec-monitor/hooks/before_delegation.ts Quality gates
afterExecution exec-monitor/hooks/after_execution.ts Checkpoint save
analyzeTask subagent-observability/hooks/task_analyzed.ts Metrics collection
makeRoutingDecision exec-monitor/hooks/route_decision.ts Runtime suggestion
decomposeTask Taskr/hooks/decomposition_requested.ts Decomposition strategy
calculateComplexity subagent-observability/hooks/task_analyzed.ts Score enhancement
saveCheckpoint exec-monitor/services/checkpoint_manager.ts Persistence
restoreCheckpoint exec-monitor/hooks/checkpoint_restore.ts Recovery

4. Event Mapping

4.1 Old Hook Names → New Event Names

Phase 3 Hook Phase 4+ Event Handler File
beforeDelegation BEFORE_DELEGATION plugins/exec-monitor/hooks/before_delegation.ts
afterExecution AFTER_EXECUTION plugins/exec-monitor/hooks/after_execution.ts
analyzeTask TASK_ANALYZED plugins/subagent-observability/hooks/task_analyzed.ts
decomposeTask DECOMPOSITION_REQUESTED plugins/taskr/hooks/decomposition_requested.ts
makeRoutingDecision ROUTE_DECISION plugins/exec-monitor/hooks/route_decision.ts
validateQuality QUALITY_GATE plugins/exec-monitor/hooks/quality_gate.ts
saveCheckpoint CHECKPOINT_SAVE plugins/exec-monitor/hooks/checkpoint_save.ts
loadCheckpoint CHECKPOINT_RESTORE plugins/exec-monitor/hooks/checkpoint_restore.ts

4.2 Payload Changes

Phase 3 (Internal object):

{
  task: { id, description, steps, files },
  complexity: 5,
  operatorLevel: "L3",
}

Phase 4+ (Event payload):

interface TaskAnalyzedEvent {
  task: {
    id: string;
    description: string;
    steps?: number;
    files?: string[];
    estimatedDuration?: number;
    priority?: "low" | "normal" | "high" | "urgent";
  };
  complexity: {
    total: number;        // 1-10
    breakdown: {
      steps: number;
      files: number;
      dependency: number;
      determinism: number;
    };
    keywords: string[];
  };
  operatorLevel: "L1" | "L2" | "L3" | "L4" | "L5";
  decompositionTriggered: boolean;
  timestamp: number;
}

Key differences:

  • Complexity is now an object with breakdown (not just a number)
  • New keywords array for detected complexity factors
  • New decompositionTriggered flag
  • Added timestamp for event ordering

4.3 Return Type Changes

Phase 3:

// Simple return value
return { pass: true, checks: [...] };

Phase 4+:

// Event-specific return type
interface BeforeDelegationResult {
  block: boolean;           // NEW: Can block delegation
  checks: Check[];
  enhancedRoutingSuggestion?: {  // NEW: Can suggest routing change
    runtime: "subagent" | "acp";
    agentId: string;
    reason: string;
  };
}


5. Breaking Changes

5.1 API Changes

Change Phase 3 Phase 4+
Entry point Direct function call Event-driven via registerHook
Complexity type number (1-10) object with breakdown
Return structure Direct result Event-specific result wrapper
State management Module-level state Service-based state
Configuration config.execMonitor Per-plugin config schema

5.2 Configuration Changes

Phase 3 (exec-monitor config):

{
  "execMonitor": {
    "enabled": true,
    "qualityGate": {
      "strict": true
    },
    "checkpoint": {
      "enabled": true,
      "intervalMs": 30000
    }
  }
}

Phase 4+ (per-plugin config):

{
  "plugins": {
    "exec-monitor": {
      "enabled": true,
      "qualityGate": {
        "strict": true
      }
    },
    "subagent-observability": {
      "enabled": true,
      "rateLimit": {
        "maxEventsPerSecond": 100
      }
    },
    "taskr": {
      "enabled": true,
      "storage": {
        "type": "json_file",
        "path": "~/.openclaw/taskr.json"
      }
    }
  }
}

5.3 Import Path Changes

Phase 3:

const execMonitor = require("./exec-monitor");
const result = await execMonitor.beforeDelegation(task);

Phase 4+:

import { SUBAGENT_COORDINATOR_EVENTS } from "./events";

// Plugins import from events.ts
import type { BeforeDelegationEvent } from "./events";


6. Testing Migration

6.1 Verify Standalone Operation

The Skill must work without any plugins installed.

# 1. Disable all plugins
openclaw plugins disable --all

# 2. Run a simple task
openclaw agent run worker --task "Copy file a.txt to b.txt"

# 3. Verify task completes using built-in fallback implementations

6.2 Test with Plugins

# 1. Enable plugins one by one
openclaw plugins enable subagent-observability
openclaw plugins enable taskr
openclaw plugins enable exec-monitor

# 2. Run same task
openclaw agent run worker --task "Copy file a.txt to b.txt"

# 3. Verify enhanced behavior (metrics recorded, etc.)

6.3 Test Event Flow

// Test script to verify events are triggered
import { SUBAGENT_COORDINATOR_EVENTS } from "./events";

async function testEventFlow() {
  const events: string[] = [];

  // Listen to all events
  for (const eventName of Object.values(SUBAGENT_COORDINATOR_EVENTS)) {
    eventBus.on(eventName, (payload) => {
      events.push(eventName);
    });
  }

  // Execute a task
  await executeTask("Copy file a.txt to b.txt");

  // Verify expected events fired
  console.log("Events fired:", events);

  const expectedEvents = [
    SUBAGENT_COORDINATOR_EVENTS.TASK_ANALYZED,
    SUBAGENT_COORDINATOR_EVENTS.QUALITY_GATE,
    SUBAGENT_COORDINATOR_EVENTS.BEFORE_DELEGATION,
    SUBAGENT_COORDINATOR_EVENTS.AFTER_EXECUTION,
  ];

  for (const expected of expectedEvents) {
    if (!events.includes(expected)) {
      throw new Error(`Expected event ${expected} was not fired`);
    }
  }

  console.log("All expected events fired correctly");
}

6.4 Integration Test

# Full integration test
openclaw test integration --suite subagent-coordinator --plugins all

Expected test coverage:

  • Task analysis with complexity scoring
  • Event triggering in correct order
  • Plugin hook execution
  • Fallback behavior when plugins disabled
  • Checkpoint save/restore cycle
  • Quality gate validation

7. Rollback

7.1 Reverting to Phase 3

If Phase 4+ doesn't work for your use case:

Step 1: Disable all Phase 4+ plugins

openclaw plugins disable subagent-observability
openclaw plugins disable taskr
openclaw plugins disable exec-monitor

Step 2: Verify Skill works with fallbacks

openclaw agent run worker --task "List files in current directory"

The Skill should work using built-in fallback implementations.

Step 3: If you need exec-monitor functionality

Revert to Phase 3 exec-monitor by restoring from backup:

# Assuming you have a backup
cp -r /path/to/backup/exec-monitor /path/to/subagent-coordinator/

# Or install the bundled exec-monitor
npm install subagent-exec-monitor@3.0.0

7.2 Reverting Plugin Config

Remove plugin-specific config from openclaw.json:

{
  "plugins": {
    // REMOVE these entries
    "subagent-observability": { ... },
    "taskr": { ... },
    "exec-monitor": { ... }
  }
}

7.3 Partial Rollback

If only one plugin is causing issues:

# Disable specific plugin
openclaw plugins disable <plugin-name>

# Verify Skill still works
openclaw agent run worker --task "Simple task"

# The other plugins remain enabled

8. Migration Example

8.1 Complete Walkthrough

Original Phase 3 code:

// exec-monitor/src/index.js
const execMonitor = {
  beforeDelegation: async (task) => {
    const checks = [];
    if (!task.description) {
      checks.push({ name: "has_description", pass: false });
    }
    return { pass: checks.every(c => c.pass), checks };
  },

  afterExecution: async (task, result) => {
    await saveCheckpoint({ task, result, timestamp: Date.now() });
    return { saved: true };
  },
};

module.exports = execMonitor;

Phase 4+ migration:

Step 1: Create plugin structure

mkdir -p plugins/exec-monitor/src/hooks
mkdir -p plugins/exec-monitor/src/services

Step 2: Create plugin.json

{
  "id": "subagent-exec-monitor",
  "name": "Subagent Coordinator Execution Monitor",
  "version": "0.0.4",
  "runtime": "openclaw",
  "entry": "src/index.ts",
  "description": "Quality gates and checkpoints for subagent-coordinator",
  "events": [
    "subagent-coordinator:before_delegation",
    "subagent-coordinator:after_execution",
    "subagent-coordinator:checkpoint_save",
    "subagent-coordinator:checkpoint_restore"
  ],
  "services": [
    "checkpoint_manager"
  ]
}

Step 3: Create checkpoint service

// plugins/exec-monitor/src/services/checkpoint_manager.ts
interface Checkpoint {
  taskId: string;
  data: unknown;
  timestamp: number;
}

export function createCheckpointManager() {
  const checkpoints = new Map<string, Checkpoint>();

  return {
    save(taskId: string, data: unknown): string {
      const id = `cp_${taskId}_${Date.now()}`;
      checkpoints.set(id, { taskId, data, timestamp: Date.now() });
      return id;
    },

    restore(checkpointId: string): Checkpoint | null {
      return checkpoints.get(checkpointId) || null;
    },

    list(taskId: string): string[] {
      return [...checkpoints.entries()]
        .filter(([, cp]) => cp.taskId === taskId)
        .map(([id]) => id);
    },
  };
}

Step 4: Create hooks

// plugins/exec-monitor/src/hooks/before_delegation.ts
import type { BeforeDelegationEvent } from "../../../events";

export async function handleBeforeDelegation(event: BeforeDelegationEvent) {
  const { task } = event;
  const checks = [];

  if (!task.description || task.description.trim().length === 0) {
    checks.push({
      name: "has_description",
      pass: false,
      message: "Task description is empty"
    });
  }

  return {
    block: !checks.every(c => c.pass),
    checks,
  };
}

// plugins/exec-monitor/src/hooks/after_execution.ts
import type { AfterExecutionEvent } from "../../../events";

export async function handleAfterExecution(
  event: AfterExecutionEvent,
  checkpointManager: ReturnType<typeof createCheckpointManager>
) {
  const checkpointId = checkpointManager.save(event.task.id, {
    task: event.task,
    result: event.result,
    timestamp: event.timestamp,
  });

  return { saved: true, checkpointId };
}

Step 5: Create plugin entry

// plugins/exec-monitor/src/index.ts
import { SUBAGENT_COORDINATOR_EVENTS } from "../../events";
import { createCheckpointManager } from "./services/checkpoint_manager";
import { handleBeforeDelegation } from "./hooks/before_delegation";
import { handleAfterExecution } from "./hooks/after_execution";

export default definePluginEntry({
  id: "subagent-exec-monitor",
  name: "Subagent Coordinator Execution Monitor",
  version: "1.0.0",
  description: "Quality gates and checkpoints for subagent-coordinator",

  register(api) {
    const checkpointManager = createCheckpointManager();

    api.registerService({
      id: "checkpoint_manager",
      name: "Checkpoint Manager",
      methods: checkpointManager,
    });

    api.registerHook(
      SUBAGENT_COORDINATOR_EVENTS.BEFORE_DELEGATION,
      handleBeforeDelegation
    );

    api.registerHook(
      SUBAGENT_COORDINATOR_EVENTS.AFTER_EXECUTION,
      (event) => handleAfterExecution(event, checkpointManager)
    );
  }
});


9. Version Compatibility

Component Min Version Notes
subagent-coordinator Skill 4.0.0 Core skill
subagent-observability 1.0.0 Optional plugin
Taskr 1.0.0 Optional plugin
exec-monitor 4.0.0 Quality gates plugin

10. Resources


Migration guide version: 4.0.0 — For subagent-coordinator v4.0.0