Skip to content

feat(host): have the agent push unready lanes before a move to a cloud workspace - #527

Merged
iamnbutler merged 4 commits into
mainfrom
lane-push
Oct 19, 2026
Merged

iamnbutler merged 4 commits into
mainfrom
lane-push

Conversation

@iamnbutler

Copy link
Copy Markdown
Contributor

Fixes #500. Stacked on #522 (#499): land that first, then retarget this to main.

When Move to → cloud workspace finds lanes with uncommitted or unpushed work, the move no longer just fails:

  1. The host sends the channel's agent a message as the owner, in the channel's first chat, which starts a run. The message lists each unready lane with its branch, path, and problem, and asks the agent to commit each one, leaving out dependencies such as node_modules, and to lane push it. It says not to open a PR or remove any lane.
  2. The move's progress reads "Waiting for the agent to push …" until that run ends (the wait op).
  3. The host checks the lanes again. If all are pushed, the move continues to the fence, import, and start with no further action. A stopped run, or any lane still unready, stops the move with the channel where it was, and the error names the lanes left.

The step runs before the fence and before the credentials read. The record is then checked again with ready() and the move proceeds as before. A resumed move (one already fenced) skips it. The shared move() runs this step, so ace move --compute from the CLI gets it too.

move() now takes a starting wrapper, and the gateway passes lifecycle(…, "starting") through it. The listing reports computing only from the fence through the workspace's start, instead of for the whole request. While the agent runs, the chat stays open and watchable, and the app still waits out the start before it reopens the chat (#496).

Open questions, answered:

  • A run is already active: the move refuses it. A busy channel is already refused ("The channel is busy; stop its work before moving it"), and Move to offers no targets for one, so no message is queued as a follow-up or steered into someone's run.
  • Lanes with no branch: they still have to be removed by hand. Without a branch the agent has nothing to push, so the move refuses before asking the agent and names them: "These lanes have no branch to push, so remove them first: …".
  • Hosted channel moving to a cloud workspace (Move a hosted channel straight to a cloud workspace #499): the step applies there too. It is the same move() path, and the agent's run goes through the hosting service.

Smoke test (separate ACE_HOME with ace serve --loopback from this branch, the team's deployed channel and compute services, Claude Opus, project iamnbutler/toddler-game-center):

  • Local channel with a lane that had a tracked change, an untracked note, and lane-cloned node_modules: the agent committed README.md and the note but not node_modules, then ran lane push. The move continued and the workspace started, about 26 s in total. The chat stayed un-computing during the run.
  • Hosted channel with a committed but unpushed lane: the agent pushed it, and the move continued straight from the hosting service (24 s).
  • Hosted channel, ace stop during the agent's run: the move stopped with "The channel is still on ace-github-next-channel…".
  • A detached worktree under the channel's lane prefix: the move was refused at once, naming it, and no agent run started.
  • Not exercised: an agent that ends its run without pushing (the error lists the lanes left).

All test channels and their workspaces were deleted.

Built in Ace

No — Claude Code subagent outside Ace, run by the lead during a batch of fixes.

…d workspace

When a move to a cloud workspace finds lanes with uncommitted or unpushed work, the host asks the
channel's agent to commit them and lane push them, waits for that run while the move shows
progress, and checks the lanes again. A stopped run or a lane still unready stops the move with
the channel where it was. A lane with no branch is refused for the person to remove. The listing
now reports computing only from the fence on, so the chat stays open during the agent's run.

Why: apps/host/src/move.ts#function push | the agent's push runs before the fence and outside `starting`, so its run stays watchable; a lane with no branch is refused, never sent to the agent
Why: apps/host/src/move.ts#function move | after the agent's run the record is checked again with ready() before the fence, since the run can take minutes
@iamnbutler
iamnbutler changed the base branch from hosted-compute to main October 19, 2026 21:15
@iamnbutler
iamnbutler merged commit 41948aa into main Oct 19, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Have the agent push unready lanes before moving a channel to a cloud workspace

1 participant