What happened
A CoS agent worktree branch (cos/task-.../agent-...) is created with its upstream pointing at the default branch:
$ git config --get branch.cos/task-…/agent-….remote # origin
$ git config --get branch.cos/task-…/agent-….merge # refs/heads/main <-- not the branch's own ref
/do:pr's push step deliberately derives the destination from that config rather than from the local branch name (git push "$PUSH_REMOTE" "HEAD:$PUSH_BRANCH") — the guard exists so a branch whose upstream is named differently keeps pushing to the right ref. With merge=refs/heads/main, that same guard resolves to HEAD:refs/heads/main and pushes the agent's work straight to main, skipping the PR entirely. It reports success, and the branch is never published.
The existing carve-outs don't catch it: the branch has an upstream (so the "no upstream" skip doesn't apply) and the remote is a real remote, not . (so the local-upstream guard doesn't fire).
The decision
Fix it where the worktree is created rather than in slashdo — the upstream is simply wrong. When PortOS creates an agent worktree it should either set no upstream at all (git worktree add -b <branch> <path> origin/main leaves the branch untracked, which is what makes /do:pr's git push -u origin <branch> path correct), or set the upstream to the branch's own future remote ref — never to refs/heads/main.
Add a startup assertion in the same code path: after creating the worktree, fail loudly if branch.<name>.merge resolves to the default branch's ref, since every downstream push helper trusts that config.
Affected files
- The CoS worktree creation path (
server/services/ — the code that runs git worktree add for an agent task; grep for worktree add)
- Any agent bootstrap that sets
--track / --set-upstream-to on the new branch
Acceptance criteria
- A freshly created agent worktree branch has either no upstream or an upstream naming its own ref — never
refs/heads/main.
git push "$(git config --get branch.$BR.remote)" "HEAD:$(git config --get branch.$BR.merge)" in a fresh agent worktree cannot land on main.
- A test (or a boot-time assertion) covers the config shape.
Surfaced when an agent run following /do:pr pushed its commit to main instead of opening a PR.
What happened
A CoS agent worktree branch (
cos/task-.../agent-...) is created with its upstream pointing at the default branch:/do:pr's push step deliberately derives the destination from that config rather than from the local branch name (git push "$PUSH_REMOTE" "HEAD:$PUSH_BRANCH") — the guard exists so a branch whose upstream is named differently keeps pushing to the right ref. Withmerge=refs/heads/main, that same guard resolves toHEAD:refs/heads/mainand pushes the agent's work straight to main, skipping the PR entirely. It reports success, and the branch is never published.The existing carve-outs don't catch it: the branch has an upstream (so the "no upstream" skip doesn't apply) and the remote is a real remote, not
.(so the local-upstream guard doesn't fire).The decision
Fix it where the worktree is created rather than in slashdo — the upstream is simply wrong. When PortOS creates an agent worktree it should either set no upstream at all (
git worktree add -b <branch> <path> origin/mainleaves the branch untracked, which is what makes/do:pr'sgit push -u origin <branch>path correct), or set the upstream to the branch's own future remote ref — never torefs/heads/main.Add a startup assertion in the same code path: after creating the worktree, fail loudly if
branch.<name>.mergeresolves to the default branch's ref, since every downstream push helper trusts that config.Affected files
server/services/— the code that runsgit worktree addfor an agent task; grep forworktree add)--track/--set-upstream-toon the new branchAcceptance criteria
refs/heads/main.git push "$(git config --get branch.$BR.remote)" "HEAD:$(git config --get branch.$BR.merge)"in a fresh agent worktree cannot land on main.Surfaced when an agent run following
/do:prpushed its commit to main instead of opening a PR.