Skip to content

dev-loop: expose the abandon signal as POST /api/v1/agents/dev-loop/{id}/abandon and mctl_abandon_dev_loop #392

Closed

Description

@mashkovd

Problem

A DevLoopWorkflow whose proposal is deliberately not approved has no way to end from the MCP surface. It stays Running, parked on the approve wait condition, which has no timeout, indefinitely.

Live example: dev-loop-mctlhq-seerrsense-73. The proposal was superseded by a different approach (mctlhq/mctl-gitops#1363), and the issue was closed as not planned. mctl_get_dev_loop still reports status: Running.

The workflow already supports ending gracefully. DevLoopWorkflow.abandon (mctlhq/mctl-agents#420) is signalled by python -m orchestrator.temporal.cli abandon <workflow_id> --reason …. Unlike Temporal terminate, it keeps the lifecycle-ownership cleanup in _watch_pr's finally. The only path to it today is that CLI, which needs Temporal access. mctl-api exposes approve and get for dev-loop, but not abandon.

Change

  • POST /api/v1/agents/dev-loop/{workflow_id}/abandon, admin-only, body {"reason": "<required, non-empty>"}. It signals abandon with the reason plus the authenticated caller recorded as who ended it, taken from auth the same way the approve endpoint takes the approver, not from the body.
  • MCP tool mctl_abandon_dev_loop(workflow_id, reason) in internal/mcp/server.go, next to mctl_approve_dev_loop and mctl_get_dev_loop, and in the operations registry.
  • 404 for an unknown workflow_id. An already-finished execution answers with its final status instead of an error, so a retry is harmless.
  • 503 when the Temporal client is not configured, same as approve.

Verify

  • An execution parked at the approval gate actually ends on abandon. The mctl-agents#420 docstring says "at its next observation point", so confirm the approve wait_condition observes the abandon flag. If it does not, that is a mctl-agents fix, and this endpoint would be a no-op there.
  • After abandon, mctl_get_dev_loop reports a terminal status, and the result carries abandoned: <reason>.
  • The proposal's .status.yaml ends up in a terminal state (rejected/abandoned) rather than proposed. Otherwise reconcile/shepherd keep seeing it as live.

Acceptance

Run mctl_abandon_dev_loop("dev-loop-mctlhq-seerrsense-73", "superseded by mctl-gitops#1363"). It ends that execution, and the seerrsense proposal issue-73-request-media-refused-through-the-cloudf leaves proposed.

🤖 Generated with Claude Code

Activity

  1. mashkovd commented on Oct 4, 2026

    @mashkovd
    MemberAuthor

    A concrete case from 2026-10-04: two DevLoops are parked at approval for controlled test issues that must never be approved, dev-loop-mctlhq-mctl-telegram-737 and dev-loop-mctlhq-mctl-docs-124. Without this endpoint the only way to end them is a Temporal signal from inside the cluster, so they stay parked. Once this ships, abandon both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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