Preflight
Request origin
Observed need in a real workflow after a clean local LoopX reset.
Problem or unmet outcome
LoopX is product/host neutral, but the default local routes still mix product-owned .loopx state with Codex-named paths: the global registry defaults under $HOME/.codex/loopx, while project Goal state is commonly placed under .codex/goals. This is surprising outside Codex, fragments a project's state across two hidden directories, and leaves generated host commands and protocol documents coupled to a Codex-specific default.
The related runtime-route continuity defect has already been fixed in #3709: after a caller explicitly selects --runtime-root, every generated executable continuation must preserve that route. This issue is different: it proposes a host-neutral default path and a safe migration contract.
Proposed outcome
- New installations default global LoopX runtime state to
$HOME/.loopx.
- New project registrations and bootstraps store Goal-local state under
.loopx/goals/<goal-id>/, alongside the project registry.
- Every built-in route, generated CLI action, bootstrap packet, doctor result, and public document resolves the same default-path helper. Explicit
--runtime-root and documented environment overrides retain their existing precedence.
- Existing
.codex/loopx and .codex/goals state remains usable until an operator runs an explicit migration. Discovery/doctor should explain the detected legacy route and selected target.
- Migration is previewable and recoverable: validate source/target, create an auditable backup or rollback receipt, move one authoritative state set, and fail rather than leave both old and new copies writable. No silent copy-on-read or dual-authority fallback.
- Update release/install guidance and regression fixtures so they do not recreate Codex-named defaults after migration.
Scope and non-goals
In scope: runtime-root/default-path resolution, project Goal state placement, explicit migration and rollback behavior, generated command routes, docs, and cross-platform regression coverage.
Out of scope: changing Todo/quota semantics, changing output projection policy (#2881), moving arbitrary user-owned .codex files, or silently migrating existing state during ordinary commands.
Acceptance criteria
- A fresh install resolves the global registry/runtime beneath
$HOME/.loopx; a fresh project stores Goal state beneath .loopx/goals.
doctor, status, bootstrap, and generated detail_ref/continuation commands agree on the selected route.
- An explicit custom
--runtime-root continues to win and is preserved in every generated executable command, including cold-path refs.
- A legacy-only installation is detected without mutation; the explicit migration supports preview and leaves one authoritative writable state location.
- Failures during migration are recoverable from the declared backup/rollback mechanism and do not silently run against the wrong default.
- Public docs and tests contain no stale hard-coded default
$HOME/.codex/loopx or .codex/goals routes, except explicitly documented legacy-migration examples.
Alternatives considered
Keep .codex indefinitely and rely on --runtime-root: this preserves compatibility but does not make the host-neutral product default legible, and generated-command path regressions remain easier to miss.
Use a hidden compatibility symlink: rejected because it obscures authority and makes rollback/cross-platform behavior harder to reason about.
Preflight
Request origin
Observed need in a real workflow after a clean local LoopX reset.
Problem or unmet outcome
LoopX is product/host neutral, but the default local routes still mix product-owned
.loopxstate with Codex-named paths: the global registry defaults under$HOME/.codex/loopx, while project Goal state is commonly placed under.codex/goals. This is surprising outside Codex, fragments a project's state across two hidden directories, and leaves generated host commands and protocol documents coupled to a Codex-specific default.The related runtime-route continuity defect has already been fixed in #3709: after a caller explicitly selects
--runtime-root, every generated executable continuation must preserve that route. This issue is different: it proposes a host-neutral default path and a safe migration contract.Proposed outcome
$HOME/.loopx..loopx/goals/<goal-id>/, alongside the project registry.--runtime-rootand documented environment overrides retain their existing precedence..codex/loopxand.codex/goalsstate remains usable until an operator runs an explicit migration. Discovery/doctor should explain the detected legacy route and selected target.Scope and non-goals
In scope: runtime-root/default-path resolution, project Goal state placement, explicit migration and rollback behavior, generated command routes, docs, and cross-platform regression coverage.
Out of scope: changing Todo/quota semantics, changing output projection policy (#2881), moving arbitrary user-owned
.codexfiles, or silently migrating existing state during ordinary commands.Acceptance criteria
$HOME/.loopx; a fresh project stores Goal state beneath.loopx/goals.doctor, status, bootstrap, and generateddetail_ref/continuation commands agree on the selected route.--runtime-rootcontinues to win and is preserved in every generated executable command, including cold-path refs.$HOME/.codex/loopxor.codex/goalsroutes, except explicitly documented legacy-migration examples.Alternatives considered
Keep
.codexindefinitely and rely on--runtime-root: this preserves compatibility but does not make the host-neutral product default legible, and generated-command path regressions remain easier to miss.Use a hidden compatibility symlink: rejected because it obscures authority and makes rollback/cross-platform behavior harder to reason about.