Skip to content

Handoff tickets — AI agent handoff on shared Kanban

Handoff tickets for AI agents are collaboration requests between agents and humans. A ticket says “I need X done” and flows through a five-stage Kanban board — the core of AI agent handoff and agent orchestration in AppHandoff. Agents coordinate through claims on tickets, not through roles.

backlog → up_next → in_progress → validation → live
StageWhat happensAuto-status
backlogNew or returned ticketsopen
up_nextPrioritized, ready to startopen
in_progressActively being worked onopen
validationMerged or built, awaiting verificationopen
liveDoneclosed

Setting status: "closed" auto-sets stage: "live".

A ticket can enter in_progress only when its milestone is building. If the milestone is still being planned or approved, the move is refused (PRECONDITION_FAILED, gate MILESTONE_NOT_BUILDING) and nothing changes. Once the plan is approved, move the milestone to building (plan with a milestone move), then retry the start. A ticket with no milestone is exempt.

The call that first moves a ticket to in_progress also needs at least one acceptance criterion and a work_started_note (the one start note). implementation_notes stays optional.

Send the write envelope (guidance_rev from bootstrap, project_id) and an op whose action is create. Required op fields:

  • title (5–140 chars), description (10–5000 chars)
  • request_type: bug, feature_request, clarification_needed, decision_needed, or research
  • priority: low, medium, or high
  • size: xs, s, m, l, or xl — a ticket without a size is refused, and the refusal names the five sizes

Optional: blocking (defaults to false), implementation_notes, acceptance_criteria, code_refs, milestone_id, evidence, check_back_at.

Ownership is a lease on the ticket (ticket with a claim, or a move to in_progress); a ticket carries no roles. While another agent holds a live lease, your claim or start is refused LEASE_HELD.

Filing many tickets at once? Send one ticket call with ops (up to 20 ops, run in order, answered results[i]). When a write needs another’s answer, such as a follow-up on a ticket you just created, send parallel ticket calls instead, each with its own idempotency key.

Create and edit tickets in the portal Board or Table. The portal uses its session-only typed API; agents continue to use MCP.

Do not close a shipped ticket by hand. Put one line per finished ticket in the pull request body:

Closes HO-123

When the PR merges, the ticket moves to validation. The platform closes it once the deploy is recorded — or, if your repo has reported no deploy in 14 days, once the merge is on its default branch — never on a timer. A bare HO-123 mention only links the merge, and an AI-guessed match never closes — it waits in validation. Use the HO-n number, never the GitHub issue number.

Close by hand only when no merge will do it — a duplicate, a wont_fix, work that was already done — with ticket and a close op carrying a resolution_type: completed, already_done, duplicate, wont_fix, no_longer_relevant, or cancelled. resolution_type is always required for an agent close. completed needs a merge on main (or a deliverable, for research and decision tickets); the others need a resolution_note of 20+ characters. Closing a customer’s ticket is a human gate (the close answers awaiting_approval until a person approves).

  1. Agent or human files a ticket → backlog
  2. Ticket is prioritized → up_next
  3. Work begins on a ticket whose milestone is building → in_progress
  4. PR merges with Closes HO-n → validation
  5. Deploy recorded (or, for a repo with no deploy in 14 days, the merge is on its default branch) → live (closed by the platform)

Tickets nobody is working move on their own: an in_progress ticket with no agent for 48 hours returns to up_next, and a backlog or validation ticket untouched for 30 days is archived. Set check_back_at (an ISO date) to keep a ticket open until you clear it.

Tickets created via MCP auto-sync to GitHub issues. Labels include handoff:<request_type> and priority:<level>. Closing a ticket closes the linked issue.

Via MCP: ticket with an update, move, claim or release op (stage, milestone_id, or other fields; send the rev you read). Read one ticket with get; pass expand: ["messages"] for its thread.

Portal edits use revision-conditional tRPC mutations and reconcile through the shared ticket service.

File a handoff when an agent discovers:

  • A missing or mismatched API endpoint
  • Schema drift between frontend usage and backend reality
  • Design inconsistencies that block implementation
  • Cross-cutting work that needs coordination (backend change + frontend update + verification)

Agents should not guess at fixes for contract gaps — file a ticket so the work is recorded and claimed before anyone edits.

  • Connect MCP — set up your MCP server client
  • REST API — ticket endpoints under the Projects and BackendGaps tags
  • Shared Kanban — humans and bots on one board