---
id: 11135
title: Configure dev auto-sync for multiple repo clones
state: CLOSED
labels:
  - enhancement
  - ai
  - architecture
  - model-experience
assignees:
  - neo-gpt
createdAt: '2026-05-10T16:29:04Z'
updatedAt: '2026-05-12T02:08:19Z'
githubUrl: 'https://github.com/neomjs/neo/issues/11135'
author: neo-gpt
commentsCount: 0
parentIssue: null
subIssues: []
subIssuesCompleted: 0
subIssuesTotal: 0
blockedBy: []
blocking: []
closedAt: '2026-05-10T23:49:28Z'
---
# Configure dev auto-sync for multiple repo clones

## Context

Follow-up idea surfaced during review of PR #11130, which implements #11017 as a single `primary-dev-sync` Orchestrator lane. The current PR is intentionally scoped to one resolved primary checkout so it can land the safe auto-pull + KB cascade primitive first.

The operator pointed out that the live swarm topology uses three separate repo clones in three folders, one per active agent family. If the goal is to keep `dev` fresh for the whole local swarm, a single primary checkout is only the first step. The next step is an explicit configuration surface for the repo roots that should participate in dev freshness.

This is deliberately out of scope for PR #11130. It should be a follow-up ticket so the first primitive can merge without broadening its risk profile.

## The Problem

#11017 and PR #11130 close the stale-primary gap for the daemon's resolved checkout, but they do not address independent peer clones. `git worktree list --porcelain` can resolve a primary checkout from a worktree, yet it cannot discover unrelated sibling clones. The current service therefore has no authoritative way to know that other agent roots exist.

Blind auto-discovery would be risky: sibling-folder scans and matching `origin` URLs can pick up stale test clones, forks, or unrelated local experiments. Blind synchronization would be worse: an agent clone might be on a feature branch with local work, and the orchestrator must not switch branches or rewrite that working tree.

The desired surface is explicit operator configuration: "these are the repo roots that may be kept fresh," with safe per-root behavior.

## The Architectural Reality

Current PR #11130 surfaces:

- `ai/daemons/services/PrimaryRepoSyncService.mjs` resolves one primary root and runs the sync ladder.
- `ai/daemons/Orchestrator.mjs` exposes `NEO_ORCHESTRATOR_PRIMARY_DEV_SYNC_INTERVAL_MS` and `NEO_ORCHESTRATOR_PRIMARY_DEV_SYNC_ENABLED`.
- `learn/agentos/DeploymentCookbook.md` documents those two env vars.
- #11017 explicitly lists external clones as out of scope: daemons running from external clones are not addressed by the single primary-root resolver.

Adjacent but non-duplicate tickets:

- #10435 solved canonical-root overrides for `bootstrapWorktree.mjs` data symlinking in independent clones. That is clone bootstrap/data-linking, not periodic dev synchronization.
- #10822 includes a future config doctor for clone-aware config drift. That is diagnosis/migration guidance, not Orchestrator-owned dev freshness.

## The Fix

Extend the #11130 primitive from one implicit primary root to an explicit target-root list while preserving existing behavior when no list is configured.

Proposed MVP surface:

- Add an operator config env var such as `NEO_ORCHESTRATOR_DEV_SYNC_ROOTS`, containing a JSON array of absolute repo root paths.
- When unset, keep the exact #11130 behavior: resolve one primary root and sync only that root.
- When set, iterate the configured roots and apply the same safety ladder per root.
- For each root:
  - verify it is a Neo repo clone;
  - run `git fetch origin dev --quiet`;
  - if the current branch is `dev`, apply the existing dirty-state gate, metadata-only resolution, fast-forward pull, and outcome recording;
  - if the current branch is not `dev`, do not checkout/switch branches; record a safe `fetched-only` / `not-dev-branch` result.
- Keep `npm run ai:sync-kb` single-root by default. Run the KB cascade from the orchestrator's owning/root checkout after at least one successful dev update, not once per configured clone.

Naming should be reviewed during implementation. If the service remains single-root-first internally, `PrimaryRepoSyncService` can keep the name and gain `resolveTargetRoots()`. If multi-root becomes the dominant behavior, rename to a less misleading service name in the implementation PR.

## Contract Ledger Matrix

| Target Surface | Source of Authority | Proposed Behavior | Fallback | Docs | Evidence |
|---|---|---|---|---|---|
| `NEO_ORCHESTRATOR_DEV_SYNC_ROOTS` | This ticket + #11017 follow-up scope | Optional JSON array of absolute repo root paths that the Orchestrator may keep fresh | Unset preserves #11130 single-root behavior | `learn/agentos/DeploymentCookbook.md` | Unit tests for unset, malformed JSON, valid multi-root list |
| Per-root sync semantics | This ticket | Fetch every configured root; only fast-forward the working tree when current branch is `dev`; never checkout/switch branches | Non-dev branches are fetch-only and recorded as skipped/fetched-only | JSDoc on sync service | Unit tests for dev root, feature-branch root, dirty root, missing root |
| KB cascade | #11017 + this ticket | Still runs once from the orchestrator-owned/root checkout after successful dev updates | Manual `npm run ai:sync-kb` remains escape hatch | DeploymentCookbook + PR body | Unit test proves one KB invocation for multi-root cycle |
| Health outcome details | Existing HealthService task outcome envelope | Aggregate per-root result details without losing root-specific failure reasons | Failed root does not prevent other configured roots from being attempted unless config parsing fails | JSDoc | Unit test verifies partial success aggregate |

## Acceptance Criteria

- [ ] AC1: Root-list config added with no tracked machine-specific paths. The operator supplies paths via env/config, not committed source.
- [ ] AC2: Unset config preserves the PR #11130 single-primary behavior exactly.
- [ ] AC3: Config parser validates malformed JSON and non-array values with an operator-visible skipped/failed outcome.
- [ ] AC4: Each configured root is verified as a git repo with `origin/dev` before sync logic runs.
- [ ] AC5: Roots currently on `dev` use the existing dirty-state gate, metadata-only resolution, fast-forward pull, and outcome recording.
- [ ] AC6: Roots not on `dev` are not switched. They may fetch `origin/dev`, but working-tree fast-forward is skipped and recorded.
- [ ] AC7: A failure in one configured root does not prevent later roots from being inspected unless the root-list config itself is invalid.
- [ ] AC8: KB sync cascade remains single-root by default and does not run once per configured clone.
- [ ] AC9: Documentation updates `learn/agentos/DeploymentCookbook.md` with the new config surface and explicitly warns against committing local absolute paths.
- [ ] AC10: Tests cover unset config, multi-root success, feature-branch fetch-only behavior, dirty-root skip, invalid path, invalid JSON, partial success, and single KB cascade.

## Out of Scope

- Changing the underlying #11130 sync ladder.
- Auto-discovering sibling clones by filesystem scan or matching `origin` URLs.
- Switching configured roots to `dev` automatically.
- Running independent KB sync cascades for every clone.
- Moving Codex/Gemini/Claude harnesses to worktree parity.
- Solving clone config drift; #10822 covers the config-doctor direction.

## Avoided Traps

- **Auto-discovery by sibling folder scan**: rejected because the operator, not a heuristic, knows which clones are active swarm roots.
- **Branch switching**: rejected because a configured clone may be in the middle of feature work.
- **Per-clone KB sync by default**: rejected because it risks duplicated work and datastore contention. The first follow-up should keep the KB cascade single-root.
- **Bundling into PR #11130**: rejected because PR #11130 is already a coherent single-root primitive with all CI green; broadening it now increases review risk.

## Related

- Follow-up to #11017 and PR #11130.
- Adjacent non-duplicate: #10435 (`bootstrapWorktree` independent-clone canonical root).
- Adjacent non-duplicate: #10822 (clone-aware config doctor / drift detector).

Origin Session ID: `20a824b0-29d1-4082-ae12-87705ec69c3f`

Handoff Retrieval Hint: `query_raw_memories(query="PR #11130 primary-dev-sync multiple repo clones configured roots operator path list KB cascade single-root")`

## Timeline

- 2026-05-10T16:29:06Z @neo-gpt added the `enhancement` label
- 2026-05-10T16:29:07Z @neo-gpt added the `ai` label
- 2026-05-10T16:29:07Z @neo-gpt added the `architecture` label
- 2026-05-10T16:29:07Z @neo-gpt added the `model-experience` label
- 2026-05-10T16:29:07Z @neo-gpt added the `release:v13` label
- 2026-05-10T23:07:04Z @neo-opus-ada cross-referenced by #10960
- 2026-05-10T23:16:25Z @neo-opus-ada cross-referenced by #10961
- 2026-05-10T23:29:30Z @neo-gpt assigned to @neo-gpt
- 2026-05-10T23:37:16Z @neo-gpt cross-referenced by PR #11162
- 2026-05-10T23:49:29Z @tobiu closed this issue
- 2026-05-10T23:49:29Z @tobiu referenced in commit `49d54de` - "feat(orchestrator): configure dev sync roots (#11135) (#11162)

Co-authored-by: tobiu <tobiasuhlig78@gmail.com>"
- 2026-05-11T00:16:06Z @neo-gpt cross-referenced by #11169
- 2026-05-12T02:08:19Z @neo-gemini-pro removed the `release:v13` label

