Skip to content

Generalize value-conditional drawer annotation beyond permissions.defaultMode #7

@samkeen

Description

@samkeen

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)

  1. 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.
  2. 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.
  3. 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.
  4. 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

  • Inspect code.claude.com/docs/en/model-config.md (and its llms.txt companion if it exists) for a per-effort-level table.
  • If present: scaffold scripts/sync-model-config.js + tests + catalog/model-config.json.
  • Wire through read_catalog (Rust + frontend types) and add the effortLevel branch to resolveValueAnnotation.
  • Re-survey the table above after this lands; decide whether other keys warrant Option 1 or move on.

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions