Context
PR #11162 added NEO_ORCHESTRATOR_DEV_SYNC_ROOTS so the primary-dev-sync lane can update multiple explicitly configured Neo repo roots. Immediately after merge, the operator asked how the three local agent clones should actually be configured and whether there is a package script for that workflow.
V-B-A result: #11162 is merged, PrimaryRepoSyncService currently reads process.env.NEO_ORCHESTRATOR_DEV_SYNC_ROOTS, ai/scripts/orchestrator-daemon.mjs / ai/daemons/Orchestrator.mjs do not load ai/config.template.mjs or ai/config.mjs, and package.json only exposes the generic ai:orchestrator script. The current documentation is limited to the Deployment Cookbook env-var inventory row.
Duplicate sweep:
gh issue list for orchestrator dev sync roots config NEO_ORCHESTRATOR_DEV_SYNC_ROOTS returned no open duplicate.
- Knowledge Base query for this exact concept found no indexed
NEO_ORCHESTRATOR_DEV_SYNC_ROOTS documentation or ticket yet.
The Problem
The merged capability is correct but not operator-ergonomic. The current setup requires manually injecting a JSON env var into the orchestrator process:
NEO_ORCHESTRATOR_DEV_SYNC_ROOTS='["/path/to/gpt/neo","/path/to/gemini/neo","/path/to/claude/neo"]' npm run ai:orchestrator
That works for one-off launches, but it leaves three recurring gaps:
- There is no durable local place to put the machine-specific clone roots.
- There is no documented command or wrapper for the core-swarm three-clone use case.
- Adding paths to committed
package.json or ai/config.template.mjs would be wrong because the roots are operator-machine-specific.
The Architectural Reality
Relevant current surfaces:
ai/daemons/services/PrimaryRepoSyncService.mjs reads process.env.NEO_ORCHESTRATOR_DEV_SYNC_ROOTS.
ai/scripts/orchestrator-daemon.mjs starts Neo.ai.daemons.Orchestrator but does not load top-level AI config.
ai/config.template.mjs exists as a Tier 1 config candidate, but it is not currently consumed by the orchestrator path.
package.json has ai:orchestrator, but no three-root wrapper script.
learn/agentos/DeploymentCookbook.md documents the env var in the inventory row, but not the local setup flow.
The operator-local root list is a runtime/local configuration concern, not a committed template value. The clean substrate is a machine-neutral default plus gitignored local override or process-manager env injection.
The Fix
Add an operator-local configuration path for orchestrator dev-sync roots, while preserving #11162 behavior:
Keep NEO_ORCHESTRATOR_DEV_SYNC_ROOTS as the highest-precedence runtime override.
Add a local config fallback the orchestrator actually loads, e.g. ai/config.mjs / ai/config.template.mjs with a machine-neutral default:
orchestrator: {
devSyncRoots: []
}
Preserve unset behavior: empty or absent config keeps the existing single-owning-checkout sync.
Document a concrete local setup workflow for the three-clone swarm case without committing real machine paths.
Consider whether a package script should exist only as a generic launcher (for example ai:orchestrator:local) that loads the local config, not as a script hardcoding roots.
Contract Ledger Matrix
| Target Surface |
Source of Authority |
Proposed Behavior |
Fallback |
Docs |
Evidence |
NEO_ORCHESTRATOR_DEV_SYNC_ROOTS env var |
#11162 merged behavior |
Highest-precedence JSON-array override for dev-sync roots |
Existing single-root behavior when unset |
Deployment docs + local setup docs |
Unit coverage for precedence and parsing |
Local AI config (ai/config.template.mjs / gitignored local override) |
Operator follow-up after #11162 |
Machine-neutral orchestrator.devSyncRoots: [] default; local config may hold absolute roots |
Env-only behavior remains valid |
Template comments + setup docs |
Unit or smoke coverage that orchestrator passes config into PrimaryRepoSyncService |
package.json script surface |
Operator ergonomics |
Optional generic launcher only; no machine-specific paths |
Existing npm run ai:orchestrator remains valid |
README/cookbook command examples |
Static verification + one command smoke if practical |
Acceptance Criteria
Out of Scope
- Auto-discovering sibling repo clones.
- Branch switching in non-
dev clones.
- Committing real machine-specific paths for any maintainer.
- Reworking the full AI config substrate beyond the orchestrator dev-sync roots need.
Avoided Traps
- Hardcode roots in
package.json: rejected because clone paths are host-local and would break every other operator.
- Put real paths in
ai/config.template.mjs: rejected because templates must remain machine-neutral.
- Add clone auto-discovery: rejected because #11135/#11162 explicitly chose operator-configured roots to avoid unsafe filesystem probing.
- Replace env var with config: rejected because env precedence is valuable for process managers, CI, and one-off launches.
Related
- #11135 — configured dev-sync roots ticket
- PR #11162 — merged
NEO_ORCHESTRATOR_DEV_SYNC_ROOTS implementation
ai/daemons/services/PrimaryRepoSyncService.mjs
ai/scripts/orchestrator-daemon.mjs
ai/config.template.mjs
learn/agentos/DeploymentCookbook.md
Origin Session ID: 22713fa8-23d2-4b31-918b-6e2f48d69c06
Retrieval Hint: query_raw_memories(query="NEO_ORCHESTRATOR_DEV_SYNC_ROOTS ai config local three clone orchestrator")
Context
PR #11162 added
NEO_ORCHESTRATOR_DEV_SYNC_ROOTSso the primary-dev-sync lane can update multiple explicitly configured Neo repo roots. Immediately after merge, the operator asked how the three local agent clones should actually be configured and whether there is a package script for that workflow.V-B-A result: #11162 is merged,
PrimaryRepoSyncServicecurrently readsprocess.env.NEO_ORCHESTRATOR_DEV_SYNC_ROOTS,ai/scripts/orchestrator-daemon.mjs/ai/daemons/Orchestrator.mjsdo not loadai/config.template.mjsorai/config.mjs, andpackage.jsononly exposes the genericai:orchestratorscript. The current documentation is limited to the Deployment Cookbook env-var inventory row.Duplicate sweep:
gh issue listfororchestrator dev sync roots config NEO_ORCHESTRATOR_DEV_SYNC_ROOTSreturned no open duplicate.NEO_ORCHESTRATOR_DEV_SYNC_ROOTSdocumentation or ticket yet.The Problem
The merged capability is correct but not operator-ergonomic. The current setup requires manually injecting a JSON env var into the orchestrator process:
NEO_ORCHESTRATOR_DEV_SYNC_ROOTS='["/path/to/gpt/neo","/path/to/gemini/neo","/path/to/claude/neo"]' npm run ai:orchestratorThat works for one-off launches, but it leaves three recurring gaps:
package.jsonorai/config.template.mjswould be wrong because the roots are operator-machine-specific.The Architectural Reality
Relevant current surfaces:
ai/daemons/services/PrimaryRepoSyncService.mjsreadsprocess.env.NEO_ORCHESTRATOR_DEV_SYNC_ROOTS.ai/scripts/orchestrator-daemon.mjsstartsNeo.ai.daemons.Orchestratorbut does not load top-level AI config.ai/config.template.mjsexists as a Tier 1 config candidate, but it is not currently consumed by the orchestrator path.package.jsonhasai:orchestrator, but no three-root wrapper script.learn/agentos/DeploymentCookbook.mddocuments the env var in the inventory row, but not the local setup flow.The operator-local root list is a runtime/local configuration concern, not a committed template value. The clean substrate is a machine-neutral default plus gitignored local override or process-manager env injection.
The Fix
Add an operator-local configuration path for orchestrator dev-sync roots, while preserving #11162 behavior:
Keep
NEO_ORCHESTRATOR_DEV_SYNC_ROOTSas the highest-precedence runtime override.Add a local config fallback the orchestrator actually loads, e.g.
ai/config.mjs/ai/config.template.mjswith a machine-neutral default:orchestrator: { devSyncRoots: [] }Preserve unset behavior: empty or absent config keeps the existing single-owning-checkout sync.
Document a concrete local setup workflow for the three-clone swarm case without committing real machine paths.
Consider whether a package script should exist only as a generic launcher (for example
ai:orchestrator:local) that loads the local config, not as a script hardcoding roots.Contract Ledger Matrix
NEO_ORCHESTRATOR_DEV_SYNC_ROOTSenv varai/config.template.mjs/ gitignored local override)orchestrator.devSyncRoots: []default; local config may hold absolute rootsPrimaryRepoSyncServicepackage.jsonscript surfacenpm run ai:orchestratorremains validAcceptance Criteria
NEO_ORCHESTRATOR_DEV_SYNC_ROOTS.ai/config.template.mjsremains machine-neutral; no committed absolute clone paths.npm run ai:orchestratorbehavior remains valid.Out of Scope
devclones.Avoided Traps
package.json: rejected because clone paths are host-local and would break every other operator.ai/config.template.mjs: rejected because templates must remain machine-neutral.Related
NEO_ORCHESTRATOR_DEV_SYNC_ROOTSimplementationai/daemons/services/PrimaryRepoSyncService.mjsai/scripts/orchestrator-daemon.mjsai/config.template.mjslearn/agentos/DeploymentCookbook.mdOrigin Session ID: 22713fa8-23d2-4b31-918b-6e2f48d69c06
Retrieval Hint:
query_raw_memories(query="NEO_ORCHESTRATOR_DEV_SYNC_ROOTS ai config local three clone orchestrator")