Skip to content

Issue 4: Orchestrator MCP tools (in wizard-tools) #623

Description

@gewenyu99

Issue 4: Orchestrator MCP tools (in wizard-tools)

Epic: Task-queue orchestrator runner · Depends on: #622 (QueueStore) · PR: #608

Why

Agents need structured tools to seed and grow the queue, signal completion with a
handoff, and read prior handoffs. The loop guards keep dynamic enqueue from
running away.

The orchestrator tools live in the existing wizard-tools in-process MCP server,
alongside the env tools and the audit tools (audit_seed_checks,
audit_add_checks, audit_resolve_checks, wizard-tools.ts:795–953). Per-task
availability is controlled by disallowedTools and canUseTool. The tool
definitions sit in their own file and register into the one server.

Scope / deliverable

  1. Add the orchestrator tools to the wizard-tools server. Put the definitions
    in queue-tools.ts as a buildOrchestratorTools(queueStore) factory, following
    the tool(name, desc, zodSchema, handler) pattern (wizard-tools.ts:531), and
    register them in createWizardToolsServer when a QueueStore is passed
    (threaded through initializeAgent options the way askBridge is). The linear
    arm passes no QueueStore, so the tools stay off there.
  2. Tools. All mutate the in-memory QueueStore under its mutex; the disk
    reflection flushes async per Issue 3: Queue + persistence layer #622.
    • enqueue_task { type, inputs, dependsOn?, model?, reason }, for seeding and
      for dynamic enqueue. It validates type against the set of valid task types
      injected at build time (the registry is Issue 6: Agent-prompt and mini-skill format + seed prompt #625; a stub set lets Issue 4: Orchestrator MCP tools (in wizard-tools) #623 stand alone),
      rejects unknown deps, stamps depth = parentDepth + 1, enforces the guards,
      and returns the new id.
    • complete_task { taskId, status: 'done'|'failed', handoff }, the completion
      signal. handoff is a structured object validated by this tool's zod schema:
      goals (what the task was asked to achieve), did (what it did),
      forNextAgent (what the next agent should know), filesTouched?. It patches
      the in-memory task status and writes handoffs/<id>.json. The schema forces
      the agent to fill each field, so the handoff is always well-formed.
    • read_handoffs { type? | taskId? }, to read prior structured handoffs, a
      dependency's output or all upstream handoffs. Downstream tasks also get their
      dependencies' handoffs appended to their prompt automatically ( Issue 6: Agent-prompt and mini-skill format + seed prompt #625), so this
      is for opportunistic lookups.
  3. Termination and loop guards in enqueue_task. Each returns an actionable
    isError result and emits an orchestrator guard tripped event:
    • a global task budget (for example 25 tasks per run)
    • a depth cap (reject when parent.depth >= MAX_DEPTH, for example 4)
    • {type, inputs} dedup (reject a re-enqueue of existing non-failed work)
    • a per-type cap (for example 2 instrument-events)
    • the executor-loop iteration cap and the per-agent tool-call force-exit live in
      Issue 5: Executor framework + fresh per-task agent #624
  4. Add the new tool names to WIZARD_TOOL_NAMES (wizard-tools.ts:1129),
    fully qualified as mcp__wizard-tools__* (the colon form at :1126 is a known
    landmine). Leaf task types add enqueue_task to disallowedTools so
    canUseTool (agent-interface.ts:499) denies it at the tool layer.

Key files

  • new src/lib/programs/orchestrator/queue-tools.ts (buildOrchestratorTools())
  • src/lib/wizard-tools.ts (register when a QueueStore is present, extend
    WIZARD_TOOL_NAMES)
  • src/lib/programs/orchestrator/queue.ts (from Issue 3: Queue + persistence layer #622)

Acceptance criteria

  • The tools register in the wizard-tools server when a QueueStore is
    passed, and stay off on the linear arm.
  • All tools mutate the in-memory QueueStore. complete_task writes a
    structured handoffs/<id>.json and flips status.
  • enqueue_task rejects an unknown type or unknown dependsOn with an
    isError result.
  • Each guard (budget, depth, dedup, per-type) trips with an actionable message
    and emits orchestrator guard tripped { guard, type }.
  • Registered tool names are mcp__wizard-tools__*, and a leaf type with
    enqueue_task disallowed is denied by canUseTool.
  • Unit tests cover the happy path and each guard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions