openspec/changes/fix-schemas-root-selection/design.md
See proposal.md for motivation and specs/schema-resolution/spec.md for the behavioral contract.
The pre-fix CLI has two already-compatible pieces that are not connected:
schemasCommand() passes process.cwd() directly to listSchemasWithInfo().listSchemasWithInfo(projectRoot) already lists the correct project-local, user, and package schemas when given an authoritative project root.resolveRootForCommand(), which implements explicit store, nearest root, local store: pointer, global defaultStore, rootless fallback, canonicalization, and shared diagnostics.The mismatch was reproduced against the built CLI with distinct local-only and store-only schemas. From the local project, schemas --json returned local-only and omitted store-only, while context --json --store team-context resolved the operation root to the store. The relevant pre-fix test baseline passes (110 tests), so the reproduction is not caused by an existing failing suite.
Goals:
Non-Goals:
schemas --store guidance.context, templates, change creation, or the root resolver itself.propose compatibility sequence; only its stale flag-support claim changes.schemasCommand() will accept the standard store selector fields and call resolveRootForCommand() before invoking listSchemasWithInfo(root.path). This is the same boundary used by status and other root-scoped workflow commands.
Resolving inside listSchemasWithInfo() was rejected because that function is also a programmatic API with intentional backward-compatible behavior when projectRoot is omitted. Root selection is a CLI/session concern; schema enumeration should remain a pure operation over the root it receives.
The Commander registration for schemas will add --store <id> using COMMON_FLAGS.store and the shared hidden --store-path option. SchemasOptions will carry store and storePath, and command-completion metadata will add the same common store flag. Because the repository enforces that every command exposing --store is named by the shared store-selection guidance, that shared command list, committed generated skill snapshots, and generated-content parity hashes will be updated to include schemas. Formal CLI/JSON agent-contract references will be synchronized, and the existing propose compatibility flow will only lose its now-false assertion that schemas cannot accept the flag; its root-resolution sequence remains unchanged.
A raw --root or --cwd flag was rejected because it would bypass registry validation, store identity checks, canonicalization, and existing diagnostics. Asking an Agent to run cd <root.path> && openspec schemas was rejected because generated tool permissions and working-directory support differ across Agents.
The command will use resolveRootForCommand() unchanged:
--store.store: pointer.defaultStore when no nearer root exists.Invalid pointers, stale defaults, unknown stores, and the presence of unselected registered stores remain fail-closed. Adding a schemas-only catch-and-fallback path was rejected because it would recreate the mismatch this change removes.
Successful human output remains the current listing, and successful JSON remains the top-level schema array. No root metadata is added, avoiding a breaking output-shape change.
When root resolution fails under --json, the existing command adapter will emit one machine-readable failure document with an empty schema list, null root, and the shared status diagnostic. Human mode keeps the standard root banner and error/fix presentation used by other commands.
A focused CLI suite will construct real temporary roots and registered stores with distinct valid project-local schemas. It will exercise explicit store selection, local pointers, global defaults, nearest-root precedence, rootless compatibility, fail-closed errors, paths with spaces, and the hidden removed option. Completion metadata gets a focused registry assertion.
The tests will use Node path utilities and canonical fixture helpers, following test/AGENTS.md; no path identity assertion will compare non-canonical spellings.
schemas as an unscoped built-in-only listing. → Return the same actionable selection diagnostic as other root-scoped commands; selecting a store or entering a root makes the result authoritative.propose compatibility wording, but leaves feature-specific selection/confirmation behavior to that branch after this independent CLI fix merges.schemas command and --store option.propose compatibility wording already support schemas --store after this fix.--store <id>.schemasCommand() to process.cwd() without changing schema files or registered-store state.