native-ui: verify --settings theme selection end to end, then land the launch flags #241

Closed
opened 2026-08-07 01:02:19 +00:00 by coilyco-ops · 3 comments
Member

Tracks the remaining native-UI work after native-ui landed on main (themes, spinner verbs, and spinner tips for all eight roles).

The one unverified claim

Everything downstream rests on this: a composed session can receive its whole native identity as launch arguments, with no host mutation, because --settings loads into the flagSettings precedence tier.

["userSettings","projectSettings","localSettings","flagSettings","policySettings"]

Read from the Claude Code 2.1.221 binary: the tier order above, flagSettings as the --settings tier, and theme / spinnerVerbs / spinnerTipsEnabled / spinnerTipsOverride all living in the schema that tier validates, with theme accepting a custom: prefixed slug.

Not verified: that an emitted fragment passed as --settings actually selects a custom theme in a live session. That is inference from the three facts above, not an observation.

The check needs an interactive session, because print mode silently ignores settings files that fail validation, so -p would report success either way. It also needs the theme file present under <home>/.claude/themes/, since a custom: reference resolves against that directory.

Remaining work, in order

  1. Verify --settings selection interactively. Blocks the rest. If it fails, the launch path needs a different mechanism and agentic-os#962 grows back the settings-merge scope it just lost.
  2. Land the launch flags (agent-compose#236). --name <seat> plus --settings <bundle>/claude-settings.json. One code path, one job.
  3. Subagent status line (agent-compose#237). Independent of the above.
  4. Plugin packaging (agent-compose#238) and vendored list refresh (agent-compose#239). Neither blocks anything.
  5. Host convergence of the theme files (agentic-os#962). Reduced to installing eight additive files.

Done when

--settings selection is confirmed or disproven in a live session, the result is recorded on this issue, and agent-compose#236 and agentic-os#962 are corrected if it was wrong.

Tracks the remaining native-UI work after `native-ui` landed on `main` (themes, spinner verbs, and spinner tips for all eight roles). ## The one unverified claim Everything downstream rests on this: a composed session can receive its whole native identity as launch arguments, with no host mutation, because `--settings` loads into the `flagSettings` precedence tier. ``` ["userSettings","projectSettings","localSettings","flagSettings","policySettings"] ``` Read from the Claude Code 2.1.221 binary: the tier order above, `flagSettings` as the `--settings` tier, and `theme` / `spinnerVerbs` / `spinnerTipsEnabled` / `spinnerTipsOverride` all living in the schema that tier validates, with `theme` accepting a `custom:` prefixed slug. **Not verified:** that an emitted fragment passed as `--settings` actually selects a custom theme in a live session. That is inference from the three facts above, not an observation. The check needs an interactive session, because print mode silently ignores settings files that fail validation, so `-p` would report success either way. It also needs the theme file present under `<home>/.claude/themes/`, since a `custom:` reference resolves against that directory. ## Remaining work, in order 1. **Verify `--settings` selection interactively.** Blocks the rest. If it fails, the launch path needs a different mechanism and agentic-os#962 grows back the settings-merge scope it just lost. 2. **Land the launch flags** (agent-compose#236). `--name <seat>` plus `--settings <bundle>/claude-settings.json`. One code path, one job. 3. **Subagent status line** (agent-compose#237). Independent of the above. 4. **Plugin packaging** (agent-compose#238) and **vendored list refresh** (agent-compose#239). Neither blocks anything. 5. **Host convergence of the theme files** (agentic-os#962). Reduced to installing eight additive files. ## Done when `--settings` selection is confirmed or disproven in a live session, the result is recorded on this issue, and agent-compose#236 and agentic-os#962 are corrected if it was wrong.
Author
Member

Verified: --settings selects a custom theme in a live session, and beats userSettings

Observed, not inferred. Claude Code 2.1.221 on macOS, run under a pty so the TUI actually renders, with the raw output bytes captured and scanned for 24-bit foreground sequences.

Setup:

  • <home>/.claude/themes/ holds aos-design.json and aos-engineer.json, both straight from examples/claude-native-ui/themes/.
  • <home>/.claude/settings.json already carried "theme": "custom:aos-design", so the user tier had a competing selection. That makes the test a precedence check as well as a selection check.

Control, no flag:

promptBorder  38;2;143;116;184   #8f74b8   design
claude        38;2;172;143;215   #ac8fd7   design

Test, --settings examples/claude-native-ui/settings.engineer.json:

promptBorder  38;2;179;146;88    #b39258   engineer
claude        38;2;179;146;88    #b39258   engineer

Every design triple is absent from the test capture, and every engineer triple is absent from the control. So the flag both selected the custom theme and overrode the user settings file, which is what the flagSettings tier position predicted.

What this settles

  • Item 1 on this issue is done. The launch path can hand a composed session its whole native identity as launch arguments.
  • agent-compose#236 keeps both flags, --name and --settings. One insight, one code path.
  • agentic-os#962 stays reduced to installing eight additive theme files. No settings merge.

Still not observed

Theme selection only. spinnerVerbs, spinnerTipsEnabled, and spinnerTipsOverride ride the same tier and the same schema, so they are expected to apply, but a fresh screen renders no spinner and the capture shows none. Confirming those needs a probe that drives a turn.

Note for whoever repeats this: matching on prompt text needs the escape sequences stripped first. Claude Code emits a cursor-column sequence between words, so the trust prompt reads as trust\x1b[20Gthis\x1b[25Gfolder in the raw stream.

## Verified: `--settings` selects a custom theme in a live session, and beats userSettings Observed, not inferred. Claude Code 2.1.221 on macOS, run under a pty so the TUI actually renders, with the raw output bytes captured and scanned for 24-bit foreground sequences. Setup: * `<home>/.claude/themes/` holds `aos-design.json` and `aos-engineer.json`, both straight from `examples/claude-native-ui/themes/`. * `<home>/.claude/settings.json` already carried `"theme": "custom:aos-design"`, so the user tier had a competing selection. That makes the test a precedence check as well as a selection check. **Control**, no flag: ``` promptBorder 38;2;143;116;184 #8f74b8 design claude 38;2;172;143;215 #ac8fd7 design ``` **Test**, `--settings examples/claude-native-ui/settings.engineer.json`: ``` promptBorder 38;2;179;146;88 #b39258 engineer claude 38;2;179;146;88 #b39258 engineer ``` Every design triple is absent from the test capture, and every engineer triple is absent from the control. So the flag both selected the custom theme and overrode the user settings file, which is what the `flagSettings` tier position predicted. ## What this settles * Item 1 on this issue is done. The launch path can hand a composed session its whole native identity as launch arguments. * agent-compose#236 keeps both flags, `--name` and `--settings`. One insight, one code path. * agentic-os#962 stays reduced to installing eight additive theme files. No settings merge. ## Still not observed Theme selection only. `spinnerVerbs`, `spinnerTipsEnabled`, and `spinnerTipsOverride` ride the same tier and the same schema, so they are expected to apply, but a fresh screen renders no spinner and the capture shows none. Confirming those needs a probe that drives a turn. Note for whoever repeats this: matching on prompt text needs the escape sequences stripped first. Claude Code emits a cursor-column sequence between words, so the trust prompt reads as `trust\x1b[20Gthis\x1b[25Gfolder` in the raw stream.
Author
Member

State of the remaining work

  1. Verify --settings selection interactively - done, evidence above.
  2. Land the launch flags (#236) - done, main at 10a78e1. Closed.
  3. Subagent status line (#237) - done, main at 0a7683f. Closed. The tick contract turned out to be the inverse of what #237 assumed on both halves: one invocation per tick carrying every row, and strict JSONL out rather than text. Details on that issue.
  4. Plugin packaging (#238) and vendored list refresh (#239) - open, neither blocking.
  5. Host convergence of the theme files (agentic-os#962) - open, still reduced to installing eight additive files.

Two calls left on this program

#239 detection. The issue asks whether refreshing is a manual chore or something the repo detects. Detection is feasible but the shape matters. The 184 verbs sit in one JS array literal and re-extract cleanly. The theme tokens do not: the base objects are keyed identically across dark, light, dark-ansi, light-ansi, and both daltonized variants, and the name-to-object mapping is not recoverable by a simple read, so there is no honest way to re-extract the dark set specifically. What is recoverable is the union of token keys across every base, which still catches a rename as a missing key.

That suggests: pin the version in one place, vendor both lists side by side with the extraction method recorded, and check drift by comparing extracted content rather than the version string. A version-string gate would fail on every Claude Code auto-update and get bypassed within a week.

#238 packaging. The issue flags the caveat worth weighing first, and it still stands. Packaging concentrates more of the identity behind --safe-mode, and after #236 the settings half no longer needs installing at all, so the only thing packaging saves is the eight theme files. That is a much smaller prize than when the step was written.

Both are worth a human decision before implementation, so this issue is the wall.

## State of the remaining work 1. **Verify `--settings` selection interactively** - done, evidence above. 2. **Land the launch flags** (#236) - done, `main` at 10a78e1. Closed. 3. **Subagent status line** (#237) - done, `main` at 0a7683f. Closed. The tick contract turned out to be the inverse of what #237 assumed on both halves: one invocation per tick carrying every row, and strict JSONL out rather than text. Details on that issue. 4. **Plugin packaging** (#238) and **vendored list refresh** (#239) - open, neither blocking. 5. **Host convergence of the theme files** (agentic-os#962) - open, still reduced to installing eight additive files. ## Two calls left on this program **#239 detection.** The issue asks whether refreshing is a manual chore or something the repo detects. Detection is feasible but the shape matters. The 184 verbs sit in one JS array literal and re-extract cleanly. The theme tokens do not: the base objects are keyed identically across `dark`, `light`, `dark-ansi`, `light-ansi`, and both daltonized variants, and the name-to-object mapping is not recoverable by a simple read, so there is no honest way to re-extract *the dark set specifically*. What is recoverable is the union of token keys across every base, which still catches a rename as a missing key. That suggests: pin the version in one place, vendor both lists side by side with the extraction method recorded, and check drift by comparing extracted content rather than the version string. A version-string gate would fail on every Claude Code auto-update and get bypassed within a week. **#238 packaging.** The issue flags the caveat worth weighing first, and it still stands. Packaging concentrates more of the identity behind `--safe-mode`, and after #236 the settings half no longer needs installing at all, so the only thing packaging saves is the eight theme files. That is a much smaller prize than when the step was written. Both are worth a human decision before implementation, so this issue is the wall.
Author
Member

Closing. Every item on this issue is resolved.

  1. Verify --settings selection - done. Observed, evidence above.
  2. Launch flags (#236) - done, 10a78e1. Closed.
  3. Subagent status line (#237) - done, 0a7683f. Closed. Contract corrected against the binary.
  4. Plugin packaging (#238) - closed as no longer worth it. #236 shrank the prize to eight additive theme files while the --safe-mode blast radius stayed the same size.
    Vendored list refresh (#239) - done, 6cfbb56 and 3a1bf5f. Detection is by content rather than version, and it found real drift on its first run: the verb list was 184 where the harness ships 186.
  5. Host convergence of the theme files (agentic-os#962) - still open, still reduced to installing eight additive files. That lives in the other repo, so it is the only thing left and it is not this repo's to close.

What the program actually delivered

A composed Claude session receives its whole native identity as launch arguments. --name <seat> and --settings <bundle>/claude-settings.json carry the seat name, the theme selection, the spinner verbs, the tips, and now the subagent status line. Nothing is written into ~/.claude at compose or launch time. The single remaining host dependency is the theme document, and its absence degrades to losing the colors while keeping everything else.

The unverified claim this issue was opened to settle is settled, and it held.

Deferred, tracked at #242

Two inferences that need a session driving a real turn: whether Ink honors ANSI inside subagent row content, and whether the verbs and tips actually apply through --settings as their shared tier and schema predict. Neither blocks anything shipped, and both fail quietly if wrong, which is why they are written down rather than assumed.

## Closing. Every item on this issue is resolved. 1. **Verify `--settings` selection** - done. Observed, evidence above. 2. **Launch flags** (#236) - done, 10a78e1. Closed. 3. **Subagent status line** (#237) - done, 0a7683f. Closed. Contract corrected against the binary. 4. **Plugin packaging** (#238) - closed as no longer worth it. #236 shrank the prize to eight additive theme files while the `--safe-mode` blast radius stayed the same size. **Vendored list refresh** (#239) - done, 6cfbb56 and 3a1bf5f. Detection is by content rather than version, and it found real drift on its first run: the verb list was 184 where the harness ships 186. 5. **Host convergence of the theme files** (agentic-os#962) - still open, still reduced to installing eight additive files. That lives in the other repo, so it is the only thing left and it is not this repo's to close. ## What the program actually delivered A composed Claude session receives its whole native identity as launch arguments. `--name <seat>` and `--settings <bundle>/claude-settings.json` carry the seat name, the theme selection, the spinner verbs, the tips, and now the subagent status line. Nothing is written into `~/.claude` at compose or launch time. The single remaining host dependency is the theme document, and its absence degrades to losing the colors while keeping everything else. The unverified claim this issue was opened to settle is settled, and it held. ## Deferred, tracked at #242 Two inferences that need a session driving a real turn: whether Ink honors ANSI inside subagent row `content`, and whether the verbs and tips actually apply through `--settings` as their shared tier and schema predict. Neither blocks anything shipped, and both fail quietly if wrong, which is why they are written down rather than assumed.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agent-compose#241
No description provided.