Skip to content

Wire convoys end-to-end: batch sling, Mayor tools, and dead code cleanup #540

@jrf0110

Description

@jrf0110

Overview

The convoy backend infrastructure is fully implemented in the TownDO — createConvoy(), onBeadClosed() landing detection, convoy_metadata, bead_dependencies tracking. But none of it is reachable from the Mayor. The Mayor slings independent beads with no grouping, no progress tracking, and no way to check on batched work.

This issue wires convoys end-to-end: batch slinging with auto-convoy creation, Mayor visibility tools, prompt updates, and dead code cleanup.

Parent: #204

Current State

  • Mayor gt_sling: Creates one bead, assigns one polecat, dispatches. No convoy.
  • Mayor prompt: Instructs the Mayor to break work into multiple beads (5-bead decomposition example). But says nothing about convoys.
  • Mayor tools: No convoy tools exist. No gt_create_convoy, no gt_list_convoys, no gt_convoy_status.
  • TownDO.createConvoy(): Fully implemented — creates convoy bead, convoy_metadata, bead_dependencies.
  • TownDO.onBeadClosed(): Fully implemented — counts closed tracked beads, updates progress, auto-lands convoy.
  • updateBeadStatus(): Wired — closing any bead checks bead_dependencies for convoy links and calls onBeadClosed().
  • Dead code: town-convoys.table.ts, town-convoy-beads.table.ts (pre-refactor tables, never imported), orphaned convoy_id field on CreateBeadBody.

The backend works. The Mayor can't reach it.

Implementation

1. Add gt_sling_batch tool to the Mayor plugin

A new Mayor tool that creates multiple beads + a convoy in one call:

// container/plugin/mayor-tools.ts
{
  name: "gt_sling_batch",
  description: "Sling multiple beads as a tracked convoy. Use this when a task should be broken into parallel sub-tasks.",
  parameters: {
    rig_id: { type: "string", description: "Target rig ID" },
    convoy_title: { type: "string", description: "Title for the convoy (the overall task)" },
    tasks: {
      type: "array",
      items: {
        type: "object",
        properties: {
          title: { type: "string" },
          body: { type: "string" },
        },
      },
      description: "List of individual beads to create and assign to polecats",
    },
  },
}

2. Add MayorGastownClient.slingBatch()

// container/plugin/client.ts
async slingBatch(rigId: string, convoyTitle: string, tasks: { title: string; body?: string }[]): Promise<SlingBatchResult> {
  return this.post(`/api/mayor/${this.townId}/tools/sling-batch`, { rig_id: rigId, convoy_title: convoyTitle, tasks });
}

3. Add Mayor sling-batch HTTP route

POST /api/mayor/:townId/tools/sling-batch

Handler calls TownDO.slingConvoy().

4. Add TownDO.slingConvoy()

Atomic operation:

  1. Create convoy bead (type='convoy', labels=['gt:convoy']) + convoy_metadata row
  2. For each task: create bead (type='issue') + bead_dependencies row (dependency_type='tracks') linking bead → convoy
  3. For each bead: get or create polecat agent + hook bead + dispatch
  4. Set convoy_metadata.total_beads = task count
  5. Return convoy bead + all created beads + assigned agents

5. Add convoy visibility tools

gt_list_convoys — List active convoys:

{
  name: "gt_list_convoys",
  description: "List active convoys with progress. Shows how many beads are closed vs total.",
}
// Returns: [{ convoy_id, title, total_beads, closed_beads, status, created_at }]

gt_convoy_status — Detailed convoy view:

{
  name: "gt_convoy_status",
  description: "Show detailed status of a convoy: each tracked bead with status and assignee.",
  parameters: { convoy_id: { type: "string" } },
}
// Returns: { convoy_id, title, total, closed, beads: [{ bead_id, title, status, assignee }] }

6. Add client methods and HTTP routes for visibility tools

GET /api/mayor/:townId/tools/convoys          → TownDO.listConvoys()
GET /api/mayor/:townId/tools/convoys/:id      → TownDO.getConvoyStatus()

7. Update Mayor system prompt

Add convoy instructions:

  • When breaking work into multiple tasks, use gt_sling_batch to group them into a convoy
  • Use gt_list_convoys to check on active batches of work
  • Use gt_convoy_status for detailed progress on a specific convoy
  • Convoys land automatically when all tracked beads close — no manual management needed
  • When a user asks "how's X going?", check the relevant convoy first

8. Dead code cleanup

Remove:

  • src/db/tables/town-convoys.table.ts — pre-refactor standalone table, never imported
  • src/db/tables/town-convoy-beads.table.ts — pre-refactor standalone table, never imported
  • convoy_id field from CreateBeadBody in src/handlers/rig-beads.handler.ts — accepted but silently dropped

End-to-End Flow

User: "Refactor the auth module"
  → Mayor breaks into 5 tasks
  → gt_sling_batch(rig_id, convoy_title: "Refactor auth module", tasks: [...])
  → TownDO.slingConvoy()
    → create convoy bead + convoy_metadata(total_beads=5)
    → for each task: create issue bead + bead_dependency(tracks) + polecat + dispatch
  → Mayor: "Created convoy 'Refactor auth module' with 5 beads, all dispatched."

[Polecats work, beads close one by one]
  → updateBeadStatus('closed') → onBeadClosed() → convoy_metadata.closed_beads++
  → Dashboard: "Refactor auth module: 3/5"

[Last bead closes]
  → onBeadClosed() → closed_beads == total_beads → convoy lands
  → Dashboard notification: "Convoy 'Refactor auth module' landed"

User: "How's the auth refactor?"
  → Mayor calls gt_convoy_status(convoy_id)
  → "4 of 5 beads closed. Toast is working on the test update. The middleware fix is in the merge queue."

Acceptance Criteria

  • gt_sling_batch tool exists in Mayor plugin and creates N beads + 1 convoy atomically
  • gt_list_convoys tool returns active convoys with progress counts
  • gt_convoy_status tool returns detailed bead-level status for a convoy
  • Client methods and HTTP routes exist for all three tools
  • TownDO.slingConvoy() creates beads, convoy, dependencies, assigns polecats, and dispatches
  • Mayor system prompt updated with convoy instructions
  • Convoy progress updates automatically as beads close (already working)
  • Convoy lands automatically when all tracked beads close (already working)
  • Dead code removed: town-convoys.table.ts, town-convoy-beads.table.ts, orphaned convoy_id on CreateBeadBody

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestkilo-auto-fixAuto-generated label by Kilokilo-triagedAuto-generated label by Kilo

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions