Background
The drawer surfaces a value-conditional annotation under the EFFECTIVE block when it can join the row's effective value to richer per-value prose:
permissions.defaultMode
string · scalar (last-wins)
Default permission mode.
EFFECTIVE
"auto" USER · WINS
→ Auto-approves tool calls with background safety
checks that verify actions align with your request.
Currently a research preview
This was wired up in 218171a (commit on top of faa33ec). Header prose stays generic (the description of the knob); the → annotation describes the current value.
The wire-up only fires for permissions.defaultMode today because it's the only settings key whose upstream docs include a separate per-value table that we already sync (catalog/permissions.json's modes array, sourced from permissions.md's ## Permission modes).
The tension
Several other multi-value enums in catalog/settings.json would benefit from the same treatment but lack a structured per-value source upstream, so the join doesn't exist. Quick survey:
| Key |
Values |
Per-value source |
permissions.defaultMode |
7 |
✅ catalog/permissions.json |
effortLevel |
5 (low/medium/high/xhigh/max) |
❌ none — all behaviour crammed into one description paragraph |
teammateMode |
3 (auto/vertical/horizontal) |
❌ none |
viewMode |
3 |
❌ none |
env.CLAUDE_CODE_DEBUG_LOG_LEVEL |
5 |
❌ none |
tui |
2 (fullscreen/classic) |
❌ none |
defaultShell |
2 (bash/powershell) |
❌ none |
forceLoginMethod |
2 |
❌ none |
~70 enable/disable toggles |
2 |
n/a — name carries meaning |
effortLevel is the most painful because the upstream description mashes together model support matrix, default per plan, xhigh fallback rules, env override, reset command, and a doc link — all five values are mentioned but in entangled prose, not a structured per-value table.
Solution space (initial thoughts)
-
Sync upstream prose where it's structured. Surface keys like effortLevel by syncing https://code.claude.com/docs/en/model-config.md (or whichever page documents per-value behaviour). If that page has a clean per-value table — analogous to permissions.md's ## Permission modes — write sync-model-config.js parallel to sync-permissions.js, generate catalog/model-config.json, and extend resolveValueAnnotation in KeyDrawer.tsx to look up effortLevel values in it. Same recipe as permissions.
- Pro: Self-documenting, drift-detectable via the existing catalog-drift workflow.
- Con: Each new domain costs one sync script + catalog file + tests. Worth it only when the upstream page actually has a structured table.
-
Hand-curated overlay catalog. Add a single catalog/value-prose-overlay.json of shape { "<keyPath>": { "<value>": "<prose>" } }, edited by hand. resolveValueAnnotation checks this overlay before / after / instead of the per-domain catalogs.
- Pro: Flexible — covers keys whose upstream docs lack a structured table. Cheap to add a row.
- Con: Rots silently without a watchdog; we'd be writing prose Claude Code's docs already wrote elsewhere.
-
Description-prose parser. Extract per-value semantics from the existing description field on settings catalog entries that have an enum. Look for patterns like "value": prose. or \"value\" foo bar.
- Pro: No new sync work; uses what we already have.
- Con: Fragile and noisy —
effortLevel's prose has multiple sentences per value with conditional fallbacks; a parser would mis-attribute or under-extract. Likely the worst of all worlds.
-
Don't do it. For 2-value enums (tui, defaultShell), the existing single-paragraph description usually covers both values clearly. For 3-5 value enums, weigh annotation cost against the user just reading the description.
- Pro: Zero work.
- Con:
effortLevel specifically is one of the higher-value annotations — knowing what xhigh actually means is non-obvious from the value name.
Recommendation
Start with Option 1 against model-config.md. Verify upstream has a structured per-effort-level table; if so, the path mirrors permissions exactly and the catalog-drift workflow keeps it honest. If it doesn't, fall back to evaluating Options 2 vs 4 per-key.
Hand-curated overlays (Option 2) might still earn a slot for keys whose upstream docs are inherently prose-heavy and unlikely to gain a table — but only after we know how many keys that's actually true for.
Concrete next steps if picked up
Out of scope
- Anything that changes the drawer layout. The annotation slot under EFFECTIVE is the contract; generalizing it doesn't relayout.
- Annotating
enable/disable boolean toggles — the value name already carries the meaning.
Background
The drawer surfaces a value-conditional annotation under the EFFECTIVE block when it can join the row's effective value to richer per-value prose:
This was wired up in
218171a(commit on top offaa33ec). Header prose stays generic (the description of the knob); the→annotation describes the current value.The wire-up only fires for
permissions.defaultModetoday because it's the only settings key whose upstream docs include a separate per-value table that we already sync (catalog/permissions.json'smodesarray, sourced frompermissions.md's## Permission modes).The tension
Several other multi-value enums in
catalog/settings.jsonwould benefit from the same treatment but lack a structured per-value source upstream, so the join doesn't exist. Quick survey:permissions.defaultModecatalog/permissions.jsoneffortLeveldescriptionparagraphteammateModeviewModeenv.CLAUDE_CODE_DEBUG_LOG_LEVELtuidefaultShellforceLoginMethodenable/disabletoggleseffortLevelis the most painful because the upstream description mashes together model support matrix, default per plan, xhigh fallback rules, env override, reset command, and a doc link — all five values are mentioned but in entangled prose, not a structured per-value table.Solution space (initial thoughts)
Sync upstream prose where it's structured. Surface keys like
effortLevelby syncinghttps://code.claude.com/docs/en/model-config.md(or whichever page documents per-value behaviour). If that page has a clean per-value table — analogous to permissions.md's## Permission modes— writesync-model-config.jsparallel tosync-permissions.js, generatecatalog/model-config.json, and extendresolveValueAnnotationinKeyDrawer.tsxto look upeffortLevelvalues in it. Same recipe as permissions.Hand-curated overlay catalog. Add a single
catalog/value-prose-overlay.jsonof shape{ "<keyPath>": { "<value>": "<prose>" } }, edited by hand.resolveValueAnnotationchecks this overlay before / after / instead of the per-domain catalogs.Description-prose parser. Extract per-value semantics from the existing
descriptionfield on settings catalog entries that have anenum. Look for patterns like"value": prose.or\"value\" foo bar.effortLevel's prose has multiple sentences per value with conditional fallbacks; a parser would mis-attribute or under-extract. Likely the worst of all worlds.Don't do it. For 2-value enums (
tui,defaultShell), the existing single-paragraph description usually covers both values clearly. For 3-5 value enums, weigh annotation cost against the user just reading the description.effortLevelspecifically is one of the higher-value annotations — knowing whatxhighactually means is non-obvious from the value name.Recommendation
Start with Option 1 against
model-config.md. Verify upstream has a structured per-effort-level table; if so, the path mirrors permissions exactly and the catalog-drift workflow keeps it honest. If it doesn't, fall back to evaluating Options 2 vs 4 per-key.Hand-curated overlays (Option 2) might still earn a slot for keys whose upstream docs are inherently prose-heavy and unlikely to gain a table — but only after we know how many keys that's actually true for.
Concrete next steps if picked up
code.claude.com/docs/en/model-config.md(and itsllms.txtcompanion if it exists) for a per-effort-level table.scripts/sync-model-config.js+ tests +catalog/model-config.json.read_catalog(Rust + frontend types) and add theeffortLevelbranch toresolveValueAnnotation.Out of scope
enable/disableboolean toggles — the value name already carries the meaning.