Skip to content
approved Visibility internal Owner erik@uvilo.com Approver _ Created 2026-07-15 Updated 2026-07-15

Orchestration Plan 8

Scope: Fix defects and gaps identified during verification (Phase.md Items E1–E12) and re-run all open verification criteria (V1, V2, V4, V6, V8, V9).

Spec: Orchestration Spec

Prior plan: Plan 7


Task 1 — Fix Project Runner Agent MCP Configuration

E1: Project Runner agent fails with “Missing required tools: list_projects, get_project_phase” despite forge-discovery being listed in its mcpServerNames in agent-sync.ts. Root cause: for master→variant families, agent-sync.ts syncs fields from master to variants, but never updates the master agent’s own mcpServerNames from the family config. The master update (buildVariantUpdate) only copies VARIANT_FIELDS + instructions, and mcpServerNames is a SYNCED_FIELD that gets copied FROM master TO variants — never set ON the master itself.

  1. In orchestrator/src/agent-sync.ts, modify the master→variant sync logic to explicitly set mcpServerNames on the master agent from the family config (family.mcpServerNames). Add this to the masterUpdate object in the sync function.
  2. Run npx tsx agent-sync.ts --dry-run to verify the change would set mcpServerNames correctly on Project Runner and Task Runner agents.
  3. Run npx tsx agent-sync.ts live to apply the fix.
  4. Verify: spawn Project Runner via forge-spawn (monitor mode) and confirm it can call list_projects and get_project_phase without errors.

Deliverable: Project Runner and Task Runner agents have correct mcpServerNames in MongoDB. E1 resolved.


Task 2 — Fix Orchestrator SSE Client

E2: The orchestrator’s wireHandlers() uses named SSE events (addEventListener('on_run_step', ...)) while LibreChat’s SSE stream sends events via the event: SSE field. forge-spawn’s approach uses the generic message event with embedded event-field parsing — this was tested and fixed. E3: createEventSource() does not pass Authorization header to SSE streams, which would cause 401 errors. E10: Monitor-mode SSE connection errors stem from these two issues.

  1. In orchestrator/src/chat-client.ts, fix createEventSource() to pass Authorization: Bearer ${token} header in the custom fetch override. Get the token from this.auth.getValidToken() — this requires making createEventSource async or caching the token. Pattern: store the token before creating EventSource, then pass it in the fetch headers alongside User-Agent.
  2. Replace wireHandlers() to use es.addEventListener('message', handler) instead of named events. Parse the event type from the SSE data: LibreChat sends event: <type>\ndata: <json> format. The message event listener receives all events; inspect event.type or parse the data to determine which handler to invoke. Reference: forge-spawn’s SSE parsing approach in mcp-servers/forge-spawn/.
  3. Handle reconnection: if the SSE stream disconnects, use resumeStream() with ?resume=true to reconnect.
  4. Test: spawn an agent in monitor mode and verify SSE events are received, Authorization succeeds, and no “SSE connection error” occurs.

Deliverable: SSE client passes Authorization and parses events correctly. E2, E3, E10 resolved.


Task 3 — Fix Dispatcher Job Management

E5: 9 jobs stuck in “running” status (some since April 28) with no cleanup/reaper mechanism. E11: Dispatcher’s createJob doesn’t record metadata (mode, requiredTools, etc.), making debugging difficult.

  1. In orchestrator/src/dispatcher.ts, update the dispatch() function to pass metadata to db.createJob():

    await db.createJob({
      id: jobId,
      conversationId: result.conversationId,
      agentId: agent_id,
      taskPrompt: task_prompt,
      status: 'running',
      startedAt: new Date(),
      metadata: { mode: invokeMode, schedule: (params as any).schedule ?? null },
    });
  2. Add a job reaper function to orchestrator/src/db.ts (or a new orchestrator/src/reaper.ts):

    • Query all jobs with status = 'running' and startedAt < NOW() - interval '2 hours' (configurable threshold)
    • For each stale job, call chatClient.checkStatus(conversationId) to determine if the agent is actually still running
    • If the agent is completed/failed/absent, update the job status to completed or failed with completedAt = NOW()
    • Log each reaped job for audit
  3. Add a scheduled Inngest function or a startup + periodic check (every 15 minutes) that runs the reaper.

  4. Clean up the 9 currently stuck jobs by running the reaper once manually.

  5. Add a POST /jobs/reap admin endpoint for manual reaper triggers.

Deliverable: Stale running jobs are auto-detected and cleaned up. Job metadata is recorded. E5, E11 resolved.


Task 4 — Fix Agent Registration and Dead Code

E6: modelSpecs in librechat.yaml only includes 10 Forge family agents. The 9 SRP/Master/Task Runner agents are missing from the model picker. E7: upsertProject() and getActiveProjects() in db.ts are dead code — never called.

  1. Run npx tsx agent-sync.ts and capture the generateModelspecs() output. Apply the full modelSpecs block to Forge/Configs/LibreChat_Service/librechat.yaml, replacing the existing incomplete list.
  2. Verify: check the LibreChat model picker contains all 19 agents (10 Forge + 4 SRP + 2 Project Runner + 2 Task Runner + 1 Page Manager = note: verify exact count against AGENT_FAMILIES).
  3. For E7: decide disposition — either:
    • Option A (wire it up): Call upsertProject() when the dispatcher creates a job (sync project index from Phase files). Add a startup sync that reads all Phase files and populates the Project table.
    • Option B (remove it): Remove upsertProject(), getActiveProjects(), and the Project table schema if not needed now. The forge-discovery MCP already provides project data via filesystem reads.
    • Recommend Option B — the Project table adds complexity without clear benefit while forge-discovery already serves this purpose. Remove the dead code and the Project table from SCHEMA_SQL.
  4. If Option B: remove upsertProject(), getActiveProjects(), Project type, and the Project table DDL from db.ts. Drop the table from the forge database.

Deliverable: All agents appear in the model picker. Dead code removed or wired up. E6, E7 resolved.


Task 5 — Complete Schedule Configuration

E4: Missing schedules per Spec §10.1: Memory Compaction (daily) and Infrastructure Check (monthly) are not configured in SCHEDULE_CONFIG or Inngest functions.

  1. In orchestrator/src/schedules.ts, add placeholder entries for the two missing schedules. These won’t have real agent IDs yet (the agents don’t exist), but the config should be present for documentation and future use:
    memory_compaction_daily: {
      agent_id: '', // TODO: create Memory Compaction agent
      task_prompt: 'Run memory compaction across all active project learnings and WIP files.',
      mode: 'disconnect',
    },
    infrastructure_check_monthly: {
      agent_id: '', // TODO: create Infrastructure Check agent
      task_prompt: 'Check infrastructure configuration: LibreChat, Railway, Neon, Vercel, Inngest. Verify all services are healthy and configs are current.',
      mode: 'disconnect',
    },
  2. In orchestrator/src/inngest.ts, add Inngest scheduled functions for these two (with guards: if agent_id is empty, skip and log a warning instead of dispatching).
  3. Verify the /schedules endpoint returns all 4 schedules.

Deliverable: All 4 Spec schedules are configured. E4 resolved.


Task 6 — End-to-End Verification

Re-run all verification criteria that were Open in the Phase.md verification report. This task addresses V1, V2, V6, V8, V9, V12, and E12.

  1. V1 — Cron scheduling: Trigger Project Runner schedule manually via Inngest dashboard. Verify: Inngest → POST /orchestrator/run → agent invoked → AgentJob record created. Let one natural cycle run (wait for hourly Task Runner) and verify it fires.

  2. V2 — Project discovery by agent: Spawn Project Runner in monitor mode. Verify it successfully calls list_projects and get_project_phase and reports project status. (Depends on Task 1 fix.)

  3. V8 — Project Runner detects completed phases: Create a test scenario where a project phase is marked complete. Trigger Project Runner. Verify it either initiates the next phase or adds an item to Erik_Todo.md.

  4. V9 — Task Runner dispatches correct sub-agent: Add a test item to Agent_Todo.md. Trigger Task Runner. Verify it dispatches the appropriate SRP agent and updates the todo item state.

  5. V6 — Stalled agent detection and resume: Start an agent in monitor mode, then abort it mid-execution. Verify the reaper (from Task 3) detects the stalled job. Test resume by spawning a new agent in the same conversation.

  6. V12/E12 — Transcript review: Spawn a sub-agent via forge-spawn. After completion, query GET /api/convos to find the conversation. Verify: (a) it appears in chat history, (b) it has an auto-generated title, (c) tool-call details are visible in the messages.

  7. V4 — Todo/checklist MCP (E9): R4 was explicitly skipped in the Spec (marked ⏭️). The flat-file Agent_Todo.md / Erik_Todo.md approach is the current substitute. Mark V4 as “Deferred” in the Phase.md — no code change needed. Record this disposition in the Resolution Log.

  8. Update Orchestration_Phase.md: for each verified criterion, change status from 🔴 to 🟢. For each resolved item, fill in the Disposition and Action taken columns. Set V4/E9 disposition to “Deferred” (flat-file replacement is adequate for now).

Deliverable: All verification criteria verified or documented as deferred. Phase.md updated with results.


Deferred Items

#DescriptionReason
E8Dispatcher ignores mode parameter for on-demand triggersSpec §10.1 states scheduled agents run in disconnect mode only. On-demand monitor mode would require wiring up Ralph Wiggum in the dispatcher — defer to a future enhancement.
E9R4 (Todo/checklist MCP) was explicitly skippedSpec marks R4 as ⏭️. Flat-file Agent_Todo.md / Erik_Todo.md is the current substitute.