Skip to content

fix(config): restore #20's rig config get|set <dot.path> CLI (dropped by #34's wizard rebase)#40

Merged
alex-mextner merged 1 commit into
mainfrom
restore-config-getset
Jun 17, 2026
Merged

fix(config): restore #20's rig config get|set <dot.path> CLI (dropped by #34's wizard rebase)#40
alex-mextner merged 1 commit into
mainfrom
restore-config-getset

Conversation

@alex-mextner

Copy link
Copy Markdown
Owner

What & why

PR #34 (the rig setup wizard, merged as f054910) rebased over main's PR #20 (rig config get|set, 635eaf5) and kept the wizard's schema-key config CLI while deleting #20's dot-path CLI (cmd_config + helpers + the argparse parser + the whole tests/test_config_getset.py). Only one config command can register, so the user-facing single-key editor silently regressed from the dot-path design to a schema-key one. This restores #20's dot-path CLI as the user-facing rig config get|set, coexisting with the wizard.

rig config get|set (restored — #20's design)

  • get <dot.path> [--global] [--json] — reads ONE nested key from the single target file (./rig.yaml, or ~/.config/rig/config.yaml with --global) — not the cascade. Missing file / absent path exits non-zero; a mapping/list subtree prints as YAML; --json emits the JSON value; diagnostics go to stderr so get --json | jq keeps a clean stdout.
  • set <dot.path> <value> [--global] [--no-apply] — conservative coercion (true/false/int/float/null; leading-zero, 1e3, nan/inf, underscored, and Unicode digits stay strings; quote-wrap forces a literal string), creates intermediate mappings, guards the write with two pre-apply gates (schema.validate, then a catalog-backed plan build over the cascade), rolls the file back on any failure, and reconciles via the same engine as rig apply on success. --no-apply writes + prints the plan only. A repo-local set refuses when ./rig.yaml is absent. Setting the removed scope key is refused.

Reconciliation (what was kept / removed, and why)

  • The dot-path engine (split_path/get_path/set_path/coerce_scalar/read_yaml_file) was never deletedfeat(setup): rig setup interactive config wizard + rig config get|set #34 left it in riglib/config.py as an orphaned util — so this PR restores only the CLI front-end (cmd_config, _cmd_config_get, _cmd_config_set, _config_target, _read_target_yaml, the parser) + tests/test_config_getset.py. The shared helpers (_load_plan/_print_plan/_print_results/_validate_layer_in_isolation/_fmt_scalar) already existed identically in main.
  • The wizard stays as rig setup. Its schema-key engine (owning-layer routing, effective_value, coerce, version-seeding) is internal to the wizard (setup_wizard.py/schema.py) — it is NOT the config get|set command. The wizard reads/writes config via its own helpers, so dropping main's schema-based cmd_config breaks nothing.
  • Removed the now-orphaned _fmt_config_value (its sole caller was the replaced cmd_config; feat(cli): add rig config get|set <dot.path> — read/edit one key, then reconcile #20 uses the identical _fmt_scalar).
  • schema.option_for_key is now unreferenced in production but kept — it is a public registry API, still tested, orphaned-by-this-deliberate-replacement (dead-code rule: investigate, don't delete).
  • Removed the schema-key config get|set CLI tests from tests/test_setup_wizard.py (their CLI surface is replaced). The schema engine they exercised stays covered by the surviving test_coerce_*/test_effective_value_*/test_writable_layer_* and the wizard-interactive tests.
  • Docs reconciled (README, AGENTS.md, docs/config-schema.md); the wizard's NON_INTERACTIVE_USAGE updated to the dot-path + reconcile framing.

Verification

  • Full suite 800 passed, 8 skipped; tests/smoke.sh OK; gitleaks clean.
  • Live-verified: get / --json / subtree-as-YAML / --global / --no-apply, the conservative-coercion edge cases (09/1e3/nan/1_000/Unicode-digit all stay strings), and the no-file + scope guards.
  • Reviewed via review --staged (multi-model) + an in-harness multi-angle review.

Deferred follow-ups (pre-existing #20 behavior, not regressions of this restore — see linked issues)

  • rig config set --global from a repo with no ./rig.yaml is not gated by the no-committed-source guard (only the non-global path is), so a --global set there reconciles built-in default repo actions. This is feat(cli): add rig config get|set <dot.path> — read/edit one key, then reconcile #20's behavior; the docs over-promise the guard for --global.
  • The post-write rollback's except Exception collapses structured RigError exit codes (e.g. unknown-item 4) to a flat 2 during a set reconcile.

These are #20's design choices, deliberately left faithful to the restore rather than redesigned in a restoration PR.

🤖 Generated with Claude Code

…ed by #34's wizard rebase)

PR #34 (the `rig setup` wizard, merged as f054910) rebased over main's PR #20
(`rig config get|set`, 635eaf5) and kept the wizard's schema-key config CLI while
deleting #20's dot-path CLI (cmd_config + helpers + parser + tests/test_config_getset.py).
Only one `config` command can register, so the user-facing single-key editor
regressed from the dot-path design to a schema-key one. This restores #20's
dot-path CLI as the user-facing command, coexisting with the wizard.

`rig config get|set` (restored, #20's design):
- get <dot.path> [--global] [--json]: reads ONE nested key from the single target
  file (./rig.yaml, or ~/.config/rig/config.yaml with --global) — NOT the cascade.
  Missing file / absent path exits non-zero; a mapping/list subtree prints as YAML;
  --json emits the JSON value; diagnostics go to stderr.
- set <dot.path> <value> [--global] [--no-apply]: conservative coercion
  (true/false/int/float/null; leading-zero, 1e3, nan/inf, underscored, Unicode
  digits stay strings), creates intermediate mappings, two pre-apply gates
  (schema.validate, then a catalog-backed plan build), rolls the file back on any
  failure, reconciles via the same engine as `rig apply`; --no-apply writes + prints
  the plan only. A repo-local set refuses when ./rig.yaml is absent. Setting the
  removed `scope` key is refused.

The dot-path engine (split_path/get_path/set_path/coerce_scalar/read_yaml_file) was
never deleted — #34 left it in riglib/config.py — so this restores only the CLI
front-end (cmd_config + _cmd_config_get/_cmd_config_set + _config_target/
_read_target_yaml + the argparse wiring) plus tests/test_config_getset.py. The
shared helpers (_load_plan/_print_plan/_print_results/_validate_layer_in_isolation/
_fmt_scalar) already existed identically in main.

The wizard stays as `rig setup`. Its schema-key engine (owning-layer routing,
effective_value, coerce, version-seeding) is internal to the wizard
(setup_wizard.py/schema.py) and is not the `config get|set` command. The wizard
reads/writes config via its own helpers, so dropping main's schema-based cmd_config
breaks nothing in it. Removed the now-orphaned _fmt_config_value (its sole caller
was the replaced cmd_config; #20 uses the identical _fmt_scalar). schema.option_for_key
is now unreferenced in production but kept (public registry API, still tested,
orphaned-by-this-replacement; dead-code rule: investigate, don't delete).

Tests: restored tests/test_config_getset.py (59 tests). Removed the schema-key
`config get|set` CLI tests from tests/test_setup_wizard.py (their CLI surface is
replaced; the schema engine they exercised stays covered by the surviving
test_coerce_*/test_effective_value_*/test_writable_layer_* and the wizard-
interactive tests). Docs reconciled (README, AGENTS.md, docs/config-schema.md);
the wizard's NON_INTERACTIVE_USAGE updated to the dot-path + reconcile framing.
Full suite 800 passed / 8 skipped; smoke OK; gitleaks clean. Live-verified:
get/--json/subtree/--global/--no-apply, coercion edge cases, no-file + scope guards.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@alex-mextner alex-mextner merged commit 18d0147 into main Jun 17, 2026
13 checks passed
@alex-mextner alex-mextner deleted the restore-config-getset branch June 17, 2026 15:26

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 948bc70682

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread riglib/cli.py
else:
state.write(target)
plan, _loaded, _env = _load_plan(args.cwd, config=None)
except Exception as exc: # noqa: BLE001

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve structured plan-build errors

When a dot-path edit reaches the second gate but plan.build rejects it with a structured RigError—for example rig config set ci.items.typo.enabled true or a removed mcp.items.review entry—this broad catch swallows UnknownItemError, prints only a generic class/name, and always returns exit 2. rig apply lets the same error reach errors.guard, which renders the what/why/fix block and exits 4, so this new config set path loses the stable CLI semantics and actionable fix text even though it rolls the file back.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant