Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/.vitepress/rfd-summaries.json
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,15 @@
"summary": "Add `jp completions` and `jp manpage` subcommands using clap_complete and clap_mangen for shell integration."
},
"060-config-explain.md": {
"hash": "cfa8458677aef01bb18793dab19605f67968b23ad00905a9d02dbd1bc7647bc0",
"hash": "9aab2d559dfa612cc7580293424e57a9cd7b0887b1b7766ac5e8dd2a39b123d3",
"summary": "Global `--explain` flag traces config resolution through 9 layers, showing where each field value originates."
},
"061-interactive-config.md": {
"hash": "0b3bcc7ed9bbafde9e3599e05238320856c4e5711af34cc35dbade7d4d0ecbc8",
"summary": "Bare `--cfg` flag triggers interactive configuration browser for searching, inspecting, and editing config fields with type-appropriate prompts."
},
"062-cli-usage-tracking.md": {
"hash": "2a7d38872df128034bd34fa8df7030af0d7f0e97a06cf5d9d522631818805e04",
"summary": "Adds local-only CLI usage tracking to record command invocations and argument patterns per workspace for adaptive features."
}
}
29 changes: 20 additions & 9 deletions docs/rfd/060-config-explain.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,17 +322,28 @@ trait IntoPartialAppConfig {
struct CliRecord {
/// The config field path. Compile-time constant.
field: &'static str,
/// The CLI flag that set it. Compile-time constant.
flag: &'static str,
/// The raw value as provided by the user.
raw_value: String,
/// The clap argument ID that set it (e.g. `model`, `no_reasoning`).
/// Compile-time constant.
arg_id: &'static str,
/// Optional note (e.g., "resolved via alias").
note: Option<String>,
}

struct CliRecorder(Vec<CliRecord>);
```

`CliRecord` stores only the config field path, the clap argument ID, and an
optional transformation note. It does **not** store the raw value or the display
flag name (`--model`, `-m`). Both can be looked up at render time:

- **Raw value**: from `ArgMatches::get_raw(arg_id)`, which is available in
`run_inner()` via Clap's `Cli::command().get_matches()`.
- **Display flag name**: from the `Command` definition via
`Command::find_subcommand()` and `Arg::get_long()` / `Arg::get_short()`.

This avoids cloning raw values in every `apply_*` helper and keeps the recorder
lightweight — just two `&'static str` pointers and an occasional note.

The helper functions that bridge CLI flags to config fields record their
assignments:

Expand All @@ -346,12 +357,12 @@ fn apply_model(
partial.assistant.model.id = id.into();

if let Some(rec) = recorder {
rec.record("assistant.model.id", "--model", id, None);
rec.record("assistant.model.id", "model", None);
}
}
```

The `&'static str` for `field` and `flag` means these are compile-time
The `&'static str` for `field` and `arg_id` means these are compile-time
constants, not runtime strings constructed elsewhere. The mapping lives next to
the code that performs the mapping — the only place that can keep it accurate.

Expand Down Expand Up @@ -473,9 +484,9 @@ Did you mean one of:
- **CLI recorder is opt-in per call site**: Each `apply_*` helper that bridges a
CLI flag to a config field needs a `recorder.record(...)` call. Forgetting to
add one when a new flag is introduced means the diff still shows the field
changed, but without the flag annotation. A test validates that recorded field
paths are valid, but cannot detect missing recordings — that requires code
review discipline.
changed, but without the flag annotation. A test validates that recorded
`arg_id` values match real clap argument IDs and that field paths are valid,
but cannot detect missing recordings — that requires code review discipline.

- **Inheritable config complexity**: When `inherit = false` is set, the explain
output needs to show which layers were skipped and why. This adds conditional
Expand Down
Loading
Loading