Sunset: agents self-refresh own clone (dev pull + config migrate)
Context
Operator friction report (@tobiu, 2026-06-10 night-shift boot): after tonight's convergent team sunset, none of the agents refreshed their repos — the operator had to walk N per-agent clones manually (switch to dev, pull, refresh config files). Direct quote of the desired behavior: "switch to dev branch (not inside a worktree), pull, update config files (e.g. via ai/scripts/setup/initServerConfigs.mjs)".
Operator explicitly requested exactly ONE agent file this ticket; claim was broadcast via A2A ([lane-claim], @neo-fable, 2026-06-10T18:37Z) before drafting. Converged by operator directive — no fan-out (lead-role Guard B Level 1 satisfied).
Live latest-open sweep: checked the latest 40 open issues via the github-workflow MCP at 2026-06-10T18:35Z; no equivalent found. Historical sweep: grep over resources/content/issues/ + KB semantic sweep (refs #11731/#11788/#11790/#11791/#12650 reviewed) — closest lineage is #11013 and #12650, both CLOSED and both distinct (see Related).
Meta-skill check (§1b): change is confined to the references/ Atlas payload (session-sunset-workflow.md); zero bytes added to the top-level SKILL.md router or any turn-loaded substrate — adheres to Progressive Disclosure.
The Problem
.agents/skills/session-sunset/references/session-sunset-workflow.md Step 1 (Codebase Synchronization) still encodes a 2-class harness taxonomy that has drifted from deployment reality:
- "Shared Checkout (Antigravity/Gemini)" →
git checkout dev && git pull origin dev (no config migration).
- "Isolated Worktree (Claude Code)" → push HEAD only; primary-checkout staleness is handled by an operator-reminder probe (
#11013): the agent computes BEHIND and asks the operator to run the pull + initServerConfigs.mjs --migrate-config manually.
Today's topology is per-agent dedicated clones (each named maintainer owns a full clone; worktrees are created per-PR inside them). A per-agent clone matches neither taxonomy branch cleanly, so at sunset agents leave their clones on stale dev (or parked on a PR branch) with stale gitignored config.mjs overlays. The next session's MCP servers boot before the agent's first turn (Step 1's own rationale, line 54), so they boot from pre-merge code + stale config — and the operator is left manually refreshing N clones between shifts.
The empirical anchor is tonight's convergent sunset (Origin Session ID below): the sunset executed cleanly per protocol, and the protocol itself never instructed any agent to refresh its own clone.
The Architectural Reality
session-sunset-workflow.md:52-55 — Step 1 harness-name taxonomy (Shared Checkout vs Isolated Worktree).
session-sunset-workflow.md:57-86 — #11013 staleness probe: detection is agent-side, execution is operator-side (reminder block, line 82, including the --migrate-config step added via #12650's scope).
ai/scripts/setup/initServerConfigs.mjs:38 — MIGRATE_FLAG = '--migrate-config'; idempotent Tier-1 import materialization (verified at source). A git pull alone updates config.template.mjs but NOT the gitignored config.mjs operator-overlay daemons/servers actually read — the flag closes that gap.
- Mechanical checkout-class detection:
git rev-parse --git-dir equals git rev-parse --git-common-dir in a primary clone; they diverge inside a linked worktree (verified live in a per-agent clone: both return .git). This replaces harness-name guessing with a git-native predicate.
The Fix
Restructure Step 1 around the mechanical predicate instead of harness names:
if [ "$(git rev-parse --git-dir)" = "$(git rev-parse --git-common-dir)" ]; then
[ -z "$(git status --porcelain)" ] || { echo 'dirty tree — skip refresh, surface in handover'; }
git switch dev
git pull origin dev
node ai/scripts/setup/initServerConfigs.mjs --migrate-config
else
:
fiProse requirements for the rewritten Step 1:
- Primary-clone branch (new): porcelain-clean guard →
git switch dev → git pull origin dev → node ai/scripts/setup/initServerConfigs.mjs --migrate-config. Any failure (dirty tree, switch/pull/script error) is surfaced in the Step 3 handover comment and the final sunset payload — refresh is best-effort; a refresh failure must never block sunset completion.
- Linked-worktree branch: existing push-HEAD discipline +
#11013 probe retained verbatim (still correct there — a worktree cannot switch to dev while the primary holds it).
- The old "Shared Checkout (Antigravity/Gemini)" branch dissolves into the primary-clone branch — gaining the previously missing
--migrate-config step.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
session-sunset-workflow.md Step 1 (consumed by all agent families at sunset) |
.agents/skills/session-sunset/references/session-sunset-workflow.md |
Agent self-refreshes its primary clone (switch dev + pull + config-migrate) via checkout-class predicate |
Refresh failure → handover note; sunset proceeds |
The workflow doc itself |
Operator report 2026-06-10; #11013/#12650 lineage; initServerConfigs.mjs:38 flag verified |
Decision Record impact
none (no ADR governs the sunset protocol). Aligned-with #11013's Shape A/B framing: this is Shape B's completion (agent-side discipline), Shape A (daemon primary-dev-sync task) remains the long-term automation.
Acceptance Criteria
Out of Scope
- Shape A daemon automation (
primary-dev-sync periodic task in Orchestrator.mjs) — long-term path, separate ticket post-#11009 lineage.
- Boot-side refresh (
AGENTS_STARTUP.md) — too late by design: MCP servers initialize before the agent's first turn; sunset is the correct window.
- Worktree bootstrap config gaps —
#12808 (sibling, distinct surface).
- Step 2 sandman ownership — shipped via
#12650.
Avoided Traps
- Boot-time refresh instead of sunset-time: rejected — servers boot pre-first-turn, so a boot-time pull cannot fix what the servers already loaded. Sunset is the natural Operator Synchronization Point (rationale already codified at line 86).
- Daemon-only solution now: rejected — Shape A depends on Orchestrator lineage and ships nothing tonight; agent-side discipline costs zero infra and lands immediately. Shape A supersedes later (retirement trigger in AC6).
- Unconditional
git checkout dev: rejected — breaks linked worktrees (dev is held by the primary; the original #11013 concern).
- Auto-stash dirty trees: rejected — destructive-adjacent at an unattended boundary; porcelain-clean guard + handover surfacing is the safe shape.
Related
#11013 (CLOSED) — Shape B operator-reminder probe; this ticket moves execution agent-side.
#12650 (CLOSED) — Step 2 sandman prohibition + --migrate-config in the reminder text; this ticket makes the agent run it.
#12808 (OPEN) — bootstrapWorktree BOOTSTRAP_CONFIGS gap (sibling config-freshness surface).
- Epic
#12065 — Orchestrator-as-SSOT lineage for the eventual Shape A daemon task.
Origin Session ID: 5000ac5e-dabb-4f39-8a5c-e8ba55133f3d (the 2026-06-10 convergent sunset that surfaced the gap; filed by its successor session)
Retrieval Hint: "session-sunset repo self-refresh initServerConfigs migrate-config checkout-class predicate"
Sunset: agents self-refresh own clone (dev pull + config migrate)
Context
Operator friction report (@tobiu, 2026-06-10 night-shift boot): after tonight's convergent team sunset, none of the agents refreshed their repos — the operator had to walk N per-agent clones manually (switch to
dev, pull, refresh config files). Direct quote of the desired behavior: "switch to dev branch (not inside a worktree), pull, update config files (e.g. viaai/scripts/setup/initServerConfigs.mjs)".Operator explicitly requested exactly ONE agent file this ticket; claim was broadcast via A2A (
[lane-claim], @neo-fable, 2026-06-10T18:37Z) before drafting. Converged by operator directive — no fan-out (lead-role Guard B Level 1 satisfied).Live latest-open sweep: checked the latest 40 open issues via the github-workflow MCP at 2026-06-10T18:35Z; no equivalent found. Historical sweep: grep over
resources/content/issues/+ KB semantic sweep (refs#11731/#11788/#11790/#11791/#12650reviewed) — closest lineage is#11013and#12650, both CLOSED and both distinct (see Related).Meta-skill check (§1b): change is confined to the
references/Atlas payload (session-sunset-workflow.md); zero bytes added to the top-levelSKILL.mdrouter or any turn-loaded substrate — adheres to Progressive Disclosure.The Problem
.agents/skills/session-sunset/references/session-sunset-workflow.mdStep 1 (Codebase Synchronization) still encodes a 2-class harness taxonomy that has drifted from deployment reality:git checkout dev && git pull origin dev(no config migration).#11013): the agent computesBEHINDand asks the operator to run the pull +initServerConfigs.mjs --migrate-configmanually.Today's topology is per-agent dedicated clones (each named maintainer owns a full clone; worktrees are created per-PR inside them). A per-agent clone matches neither taxonomy branch cleanly, so at sunset agents leave their clones on stale
dev(or parked on a PR branch) with stale gitignoredconfig.mjsoverlays. The next session's MCP servers boot before the agent's first turn (Step 1's own rationale, line 54), so they boot from pre-merge code + stale config — and the operator is left manually refreshing N clones between shifts.The empirical anchor is tonight's convergent sunset (Origin Session ID below): the sunset executed cleanly per protocol, and the protocol itself never instructed any agent to refresh its own clone.
The Architectural Reality
session-sunset-workflow.md:52-55— Step 1 harness-name taxonomy (Shared Checkout vs Isolated Worktree).session-sunset-workflow.md:57-86—#11013staleness probe: detection is agent-side, execution is operator-side (reminder block, line 82, including the--migrate-configstep added via#12650's scope).ai/scripts/setup/initServerConfigs.mjs:38—MIGRATE_FLAG = '--migrate-config'; idempotent Tier-1 import materialization (verified at source). Agit pullalone updatesconfig.template.mjsbut NOT the gitignoredconfig.mjsoperator-overlay daemons/servers actually read — the flag closes that gap.git rev-parse --git-direqualsgit rev-parse --git-common-dirin a primary clone; they diverge inside a linked worktree (verified live in a per-agent clone: both return.git). This replaces harness-name guessing with a git-native predicate.The Fix
Restructure Step 1 around the mechanical predicate instead of harness names:
if [ "$(git rev-parse --git-dir)" = "$(git rev-parse --git-common-dir)" ]; then # PRIMARY CLONE (per-agent dedicated clone OR shared checkout) # Pre-condition: PR-branch work already committed + pushed (existing Step 1 mandate) [ -z "$(git status --porcelain)" ] || { echo 'dirty tree — skip refresh, surface in handover'; } git switch dev git pull origin dev node ai/scripts/setup/initServerConfigs.mjs --migrate-config else # LINKED WORKTREE: keep existing behavior unchanged # (push HEAD + #11013 primary-checkout staleness probe / operator-reminder block) : fiProse requirements for the rewritten Step 1:
git switch dev→git pull origin dev→node ai/scripts/setup/initServerConfigs.mjs --migrate-config. Any failure (dirty tree, switch/pull/script error) is surfaced in the Step 3 handover comment and the final sunset payload — refresh is best-effort; a refresh failure must never block sunset completion.#11013probe retained verbatim (still correct there — a worktree cannot switch todevwhile the primary holds it).--migrate-configstep.Contract Ledger Matrix
session-sunset-workflow.mdStep 1 (consumed by all agent families at sunset).agents/skills/session-sunset/references/session-sunset-workflow.md#11013/#12650lineage;initServerConfigs.mjs:38flag verifiedDecision Record impact
none(no ADR governs the sunset protocol). Aligned-with#11013's Shape A/B framing: this is Shape B's completion (agent-side discipline), Shape A (daemonprimary-dev-synctask) remains the long-term automation.Acceptance Criteria
git rev-parse --git-dirvs--git-common-dir).git switch dev→git pull origin dev→node ai/scripts/setup/initServerConfigs.mjs --migrate-config; failures surface in handover, never block sunset.#11013operator probe) retained unchanged.--migrate-config(config freshness, not just code freshness).create-skillauthoring guide before editing the skill payload; change stays inreferences/(noSKILL.mdrouter bloat).primary-dev-syncperiodic task (Shape A,#11013follow-up) ships in the Orchestrator, the agent-side refresh step compresses to a trigger note.Out of Scope
primary-dev-syncperiodic task inOrchestrator.mjs) — long-term path, separate ticket post-#11009lineage.AGENTS_STARTUP.md) — too late by design: MCP servers initialize before the agent's first turn; sunset is the correct window.#12808(sibling, distinct surface).#12650.Avoided Traps
git checkout dev: rejected — breaks linked worktrees (devis held by the primary; the original#11013concern).Related
#11013(CLOSED) — Shape B operator-reminder probe; this ticket moves execution agent-side.#12650(CLOSED) — Step 2 sandman prohibition +--migrate-configin the reminder text; this ticket makes the agent run it.#12808(OPEN) — bootstrapWorktree BOOTSTRAP_CONFIGS gap (sibling config-freshness surface).#12065— Orchestrator-as-SSOT lineage for the eventual Shape A daemon task.Origin Session ID: 5000ac5e-dabb-4f39-8a5c-e8ba55133f3d (the 2026-06-10 convergent sunset that surfaced the gap; filed by its successor session)
Retrieval Hint: "session-sunset repo self-refresh initServerConfigs migrate-config checkout-class predicate"