Client or integration
CLI
Area
Codex sync / service ownership
Summary
On a machine where the opencodex-proxy scheduled task is registered, any second OpenCodex
home is permanently refused write admission — not blocked by a race or a stale lock, but by the
ownership model itself. ocx sync can never complete from that home, so its Codex config is
never injected and its proxy never reaches ready.
Scheduler registration is machine-global. The task-definition XML that proves ownership is
per-home. A second home therefore sees "the scheduler holds the task" and "my task XML is absent"
simultaneously, which the probe reports as unproven ownership.
Reproduction
- On a machine where OpenCodex is installed normally and the
opencodex-proxy scheduled task is
registered from home A.
- Create an unrelated home B (
HOME / USERPROFILE / CODEX_HOME pointing at a fresh
directory) with a minimal .opencodex/config.json.
- Start a proxy from home B on a free port. It starts and
/healthz is ok.
- Run
ocx sync from home B.
Actual
ocx sync prints:
Codex sync did not complete. Fix the reported Codex config issue and retry.
…and exits 1. Nothing is written. Calling the admission gate directly shows the real reason:
{
"kind": "refused",
"authority": "service-home",
"message": "Refusing to write because ownership could not be proven: Task Scheduler holds opencodex-proxy but its task XML is missing."
}
/readyz on the home-B proxy stays failed indefinitely, because readiness is gated on the
post-startup sync that just refused. /healthz stays ok, so the proxy looks healthy while
nothing it needs to inject has been injected.
Expected
Either:
- ownership is evaluated per home, so a home that does not claim the scheduled task is not judged
against another home's registration; or
- the refusal is explicit and actionable — it names the owning home, and
ocx sync surfaces the
reason and exits non-zero.
Why this is hard to diagnose
The admission gate produces a precise message and the CLI discards it, so the operator sees an
instruction ("fix the reported Codex config issue") referring to a report that was never printed.
The process does exit non-zero, but the actionable refusal reason is still hidden. #1461 fixed the
injection-preflight diagnostic, but this refusal comes from the earlier machine-global service-home
admission gate, whose message still never reaches the operator.
Impact
Any multi-home use of the CLI on one machine: staging or a second profile alongside a normal
install, CI on a developer machine, or testing a candidate build without disturbing the working
one. There is no configuration that avoids it, because the collision is between a machine-global
registration and a per-home proof.
Notes
Found while validating an unrelated change in an isolated second home; the workaround there was
the code's own CodexSyncDeps.admitCodexWrite test seam, which is not available to operators.
Correction after a clean re-run: an earlier version of this report said ocx sync exited 0. The
real CLI exits 1. The earlier 0 came from reading the status of a later command in a shell pipeline,
not the ocx sync process itself. The ownership refusal and swallowed diagnostic reproduce
unchanged.
Version
Reproduced again against upstream dev @ 80e251a4db5ab600ef0a0b44c9d24b326c37d40b (2.35.0),
built from source in an isolated dev/staging environment (isolated home, isolated port). This is
after #2815; that Windows sync fix does not change this service-home admission path, and the issue
still reproduces.
Operating system
Microsoft Windows 11 Pro, version 25H2, build 26200.9168, 64-bit.
Client or integration
CLI
Area
Codex sync / service ownership
Summary
On a machine where the
opencodex-proxyscheduled task is registered, any second OpenCodexhome is permanently refused write admission — not blocked by a race or a stale lock, but by the
ownership model itself.
ocx synccan never complete from that home, so its Codex config isnever injected and its proxy never reaches
ready.Scheduler registration is machine-global. The task-definition XML that proves ownership is
per-home. A second home therefore sees "the scheduler holds the task" and "my task XML is absent"
simultaneously, which the probe reports as unproven ownership.
Reproduction
opencodex-proxyscheduled task isregistered from home A.
HOME/USERPROFILE/CODEX_HOMEpointing at a freshdirectory) with a minimal
.opencodex/config.json./healthzisok.ocx syncfrom home B.Actual
ocx syncprints:…and exits 1. Nothing is written. Calling the admission gate directly shows the real reason:
{ "kind": "refused", "authority": "service-home", "message": "Refusing to write because ownership could not be proven: Task Scheduler holds opencodex-proxy but its task XML is missing." }/readyzon the home-B proxy staysfailedindefinitely, because readiness is gated on thepost-startup sync that just refused.
/healthzstaysok, so the proxy looks healthy whilenothing it needs to inject has been injected.
Expected
Either:
against another home's registration; or
ocx syncsurfaces thereason and exits non-zero.
Why this is hard to diagnose
The admission gate produces a precise message and the CLI discards it, so the operator sees an
instruction ("fix the reported Codex config issue") referring to a report that was never printed.
The process does exit non-zero, but the actionable refusal reason is still hidden. #1461 fixed the
injection-preflight diagnostic, but this refusal comes from the earlier machine-global service-home
admission gate, whose message still never reaches the operator.
Impact
Any multi-home use of the CLI on one machine: staging or a second profile alongside a normal
install, CI on a developer machine, or testing a candidate build without disturbing the working
one. There is no configuration that avoids it, because the collision is between a machine-global
registration and a per-home proof.
Notes
Found while validating an unrelated change in an isolated second home; the workaround there was
the code's own
CodexSyncDeps.admitCodexWritetest seam, which is not available to operators.Correction after a clean re-run: an earlier version of this report said
ocx syncexited 0. Thereal CLI exits 1. The earlier 0 came from reading the status of a later command in a shell pipeline,
not the
ocx syncprocess itself. The ownership refusal and swallowed diagnostic reproduceunchanged.
Version
Reproduced again against upstream
dev@80e251a4db5ab600ef0a0b44c9d24b326c37d40b(2.35.0),built from source in an isolated dev/staging environment (isolated home, isolated port). This is
after #2815; that Windows sync fix does not change this service-home admission path, and the issue
still reproduces.
Operating system
Microsoft Windows 11 Pro, version 25H2, build 26200.9168, 64-bit.