[BUG] Cloud Routines: container starts detached-HEAD over stale baked-in branch refs — `git checkout main` time-travels days back; no way to pin the checkout ref
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Summary
Cloud Routines (claude.ai/code/routines) provision the repo into the container as a detached-HEAD checkout of the current tip, laid over a cached clone whose local branch refs are frozen at environment-build time. Any agent that runs git checkout main — a completely reasonable move, especially when the routine prompt says "you are in a clone, branch main" — silently time-travels its working tree onto a days-old main ref. Agents that instead commit on the detached HEAD produce orphan chains that never reach the remote.
There is no way to pin or guarantee the checked-out ref on a routine: job_config.ccr.session_context.sources[].git_repository accepts only url. For long-running scheduled jobs that maintain state in a repo, a guaranteed start ref seems like table stakes.
Forensics (5 occurrences over 2 days, hourly routine against one private repo)
Evidence that the working-tree content is fetched fresh per run (i.e. this is not a stale snapshot of content):
- One container started detached at a commit that had been pushed to
origin/main8 minutes before the run fired. - Across all 5 occurrences the detached tip advanced with the repo.
Evidence that the local branch refs are frozen at environment build:
- One container's local
mainpointed at a commit ~6 days old (approximately when the environment was configured), genuinely diverged fromorigin/main(not an ancestor);git checkout mainmoved the working tree onto that stale content until the agent caught it viamerge-base --is-ancestor.
Impact (real, not hypothetical)
- One run committed ~50 hourly cycles of append-only journal state on the detached orphan chain, unpushed; a later run force-pushed
origin/mainto a detached tip while trying to self-rescue, temporarily replacing 11 days of granular commit history. A post-incident audit recovered everything except one cycle's worth of journal records, but only because agents had proactively pushed backup branches. - Runs that detected the condition correctly suspended their side-effecting actions for ~2 days as self-protection, because journal state on
maincould not be trusted and a concurrent second runner could not be ruled out.
Workaround
Every routine prompt now begins with git fetch origin && git checkout -B main origin/main plus a "never force-push" instruction. It works, but it lives in N prompts instead of one platform guarantee, and every agent has to be told not to trust the harness-provided checkout.
Ask
Either (or both):
- At session start, sync local branch refs to the remote and attach HEAD to the default branch, so the checkout matches what the UX implies ("a clone of your repo").
- Expose a
ref/branchfield onsources[].git_repositoryso a routine can pin "always latestorigin/main" (or a fixed tag) explicitly.
Related but distinct: #69783 (harness overrides the agent's branch on the push side; this report is about the start state).
Environment
- Product: Claude Code Routines (scheduled cloud agents, claude.ai/code/routines), Anthropic-hosted cloud environment
- Occurrences: 2026-07-16 (×2), 2026-07-17 (×3), hourly cron