Skip to content

afx: handoff / pickup commands for transferring in-flight builders between team members #1008

@amrmelsayed

Description

@amrmelsayed

Umbrella / discussion issue. Frames a collaborative-builder workflow where a team member can hand an in-flight builder to a teammate (for review, partial work, or shift change) and the teammate picks it up on their own machine. Same primitives serve both synchronous ("Alice pings Bob, Bob looks at it in 20 min, bounces back") and asynchronous ("end of day, Bob picks up tomorrow") modes. Several design calls are deliberately left open for team input rather than pre-decided.

Why this is tractable

Codev's builder model makes this less invasive than it would be in most multi-machine handoff designs:

  • The builder branch is the source of truth for builder state. Porch commits codev/projects/<id>-<name>/status.yaml to the branch on every phase transition. The thread file, plan, spec, and review artifacts all live on the branch. Once the branch is pushed to origin, a second machine has everything it needs to resume the work.
  • afx spawn --resume already exists. The missing piece is letting --resume (or a new sibling command) pull state from origin when the worktree doesn't exist locally yet, rather than demanding the worktree already exists.
  • GitHub Issues already encode ownership via the assignee field. That's the natural anchor for "who owns this builder right now", with no parallel registry to invent.
  • Inter-architect messaging exists (afx send <workspace>:architect:<name>) for the sync notification case, and gh issue comment works for the async case.

The work is mostly generalizing primitives we have, not building new infrastructure.

Proposed shape

Two coordinated commands:

Donor side (Alice has the builder):

afx handoff spir-42 --to @bob "review the spec; my concern is X"
  • Verifies the branch is at a stable boundary (between porch phases, working tree clean).
  • Pushes the branch to origin with all uncommitted porch chore commits.
  • Posts a GitHub issue comment: @bob taking over from @alice. State: at spec-approval gate. Note: ... (always — durable, async-native).
  • Fires a Tower-side message via afx send <workspace>:architect:<name> if reachable (sync ping when both are online; silent fall-through otherwise).
  • Updates the GitHub issue assignee to @bob.
  • Sets currentArchitect: bob in status.yaml and commits/pushes it.
  • Marks Alice's local worktree as read-only (see decision point Scaling Crisis - AI Autonomy Decreases as Projects Grow #3 below): worktree preserved, but afx send / spawn --resume against it errors with "currently owned by @bob; use afx pickup to take back."

Recipient side (Bob takes over):

afx pickup 42
  • Looks up issue Cannot cut and paste from terminals #42 → resolves to builder branch builder/spir-42.
  • Verifies Bob is the current GitHub assignee and status.yaml.currentArchitect == bob (the handoff actually happened).
  • git fetch && git worktree add .builders/spir-42 builder/spir-42 (or equivalent if a local worktree already exists).
  • Spawns a fresh local builder via the standard afx spawn --resume path, pointing at the existing state.
  • The new builder reads status.yaml, thread.md, and the artifacts to come up to speed (the LLM session is fresh, the project state is continuous).

Returning to the original donor uses the same commands in reverse: Bob runs afx handoff spir-42 --to @alice "feedback done; ready for spec-approval gate."

Exclusivity guard

Two architects can't both write to the same builder branch concurrently without racing on porch state and thread. The guard:

  • GitHub assignee is the public-facing source of truth.
  • status.yaml.currentArchitect: <name> is the per-branch source of truth (travels with the branch, survives clone).
  • Both are checked on every afx write against that builder (spawn --resume, send, eventually cleanup).
  • Mismatch produces a loud error pointing at the recovery command: builder spir-42 is currently owned by @bob; use 'afx pickup' to take ownership before continuing.

Open decisions for team discussion

These are the calls where preferences will affect the UX. Initial leans below; not yet committed.

1. Stable-boundary requirement on handoff

  • Option A (lean): Require the builder to be at a porch gate (between phases) and the worktree clean. State is coherent by construction, recipient lands somewhere semantically meaningful.
  • Option B: Allow handoff any time, with git status clean. More flexible, but recipient might land mid-phase with partial work the donor hasn't framed.
  • An --override flag on the strict default covers the occasional "I really need to hand off this mid-phase work" case.

2. Sync notification: try Tower message in addition to GH comment?

  • Option A (lean): Always post GH comment (durable). Additionally fire Tower-side ping if reachable (instant when both online, silent fall-through otherwise). --no-ping flag for users who find the dual-notification noisy.
  • Option B: GH comment only. Recipient sees it on next GitHub poll / notification check. Simpler, fewer moving parts.
  • Option C: Tower-only, fail the handoff if recipient is offline. Forces sync mode. Almost certainly wrong for a multi-mode design.

3. Donor's local worktree after handoff

  • Option A: Tear down completely (clean slate, fresh afx pickup later if needed). Cleanest, matches the existing afx cleanup model.
  • Option B (lean): Preserve as read-only with a currentArchitect != self marker. Re-pickup is instant (no fetch, no new worktree). Better for sync ping-pong. Risk: stale local worktree if Bob makes lots of changes before handing back. Mitigated by afx pickup doing a fast-forward fetch and refusing if there are local commits ahead of origin.
  • Option C: Just warn and keep, no read-only mark. Simplest, but lets a confused user write to a builder they no longer own and silently lose work when the recipient pushes.

4. Naming for "look without taking ownership"

A secondary primitive worth thinking about: sometimes Alice wants Bob to eyeball the spec without a full ownership transfer (Bob comments, Alice keeps going). Could be:

  • Option A (defer): Skip this for v1. Bob can just git fetch && git worktree add manually and look. Handoff is the only first-class operation.
  • Option B: afx peek <id> — fetches the branch into a read-only local checkout, no ownership transfer. Bob comments via PR review or GH issue comment.
  • Option C: Lean on existing GitHub PR review for this case entirely (the spec phase doesn't produce a PR yet, but maybe it should for review purposes).

What this isn't (for v1)

  • Not a real-time collaboration model. One owner at a time. Two architects can't both edit the worktree concurrently. The handoff dance is coordination, not concurrent editing.
  • Not multi-machine builder mirroring. The branch state is what travels; the live AI session does not. Recipient's LLM starts fresh, reading the existing artifacts to catch up.
  • Not a replacement for sibling architects within one workspace. afx workspace add-architect (existing) is for multiple architects sharing one machine / Tower. This issue is for handoffs across machines and people.

Suggested protocol when ready to build

PIR. The plumbing is small (two afx commands, a currentArchitect field, the exclusivity-check helper, the GH/Tower notification dispatch), but the decision surface is wide and benefits from a plan-gate that locks the four open decisions above before code is written. CMAP at PR catches concurrency edge cases that a single reviewer is likely to miss.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/cross-cuttingTouches multiple areas — needs coordinated handling

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions