Skip to content

Login shell contract, launch practice and landscape refresh (2026-09-29) - #498

Merged
seathatflowsinourveins merged 1 commit into
mainfrom
claude/login-shell-contract-20260929
Sep 29, 2026
Merged

seathatflowsinourveins merged 1 commit into
mainfrom
claude/login-shell-contract-20260929

Conversation

@seathatflowsinourveins

Copy link
Copy Markdown
Collaborator

Scope

  • What this PR changes, in one or two sentences: decides the open items of the terminal decision by research convergence and records the evidence. A scrub-mode claude -p probe of a peer session left an empty ~/.bash_profile that hid ~/.profile, so every new Windows Terminal tab printed exec: claude: not found (exit 127); this adds the decision-record update (cause, evidence, decisions with rejected alternatives and overturn conditions, landscape refresh), a supersession pointer on the earlier agent-view paragraph, one recipe bullet, three anti-pattern rows (this incident's and the two of the earlier update, which that change left out so its pull request could merge cleanly), the receipt and its scripts. The host changes it describes (the removed empty file, a real ~/.bash_profile that hands off to ~/.profile, and the practice repository's login-shell-path doctor check) are on the host and are not in this diff.
  • Base commit: cf2960a7 (origin/main at the last rebase)
  • Lane: lane:foundation
  • Owned paths touched: docs/decisions/2026-09-28-terminal-experience.md, recipes/claude-native-profile.md, docs/harness-defaults.md, evidence/receipts/, evidence/artifacts/login-shell-contract-20260929/, and manifests/evidence.json (hot-file protocol: main's copy taken after each rebase, own receipt entry and files re-registered, last commit).
  • Authorship: written by a Claude Sonnet 5.5 coordinator session, hence the commit trailer. Reviewed once by Codex GPT-6 (read-only, max) and a headless Opus (max); see Review.

SOTA sources

  • Bash startup order and the hand-off idiom: GNU Bash Reference Manual, "Bash Startup Files" (maintainer's copy) and bash(1) 5.2.21 INVOCATION (a login shell reads only the first of ~/.bash_profile, ~/.bash_login, ~/.profile); the Arch (dot.bash_profile) and Fedora (dot-bash_profile) bash package skeletons, which ship a ~/.bash_profile that hands off to another startup file; Ubuntu 24.04 /etc/skel/.profile (not read when ~/.bash_profile or ~/.bash_login exists).
  • anthropics/claude-code: issues #76236 (this exact empty ~/.bash_profile; closed not_planned by the stale bot 2026-09-01), #78072 (open, reproduced; maintainer comment 2026-08-17: persistent placeholders are intended, cleanup at exit is being considered), and, related and open, #94008, #81602 and #83497, all read only (nothing filed or commented); CHANGELOG.md 2.1.78, 2.1.247, 2.1.257 (/doctor warning for stale sandbox mask files) and 2.1.271; docs read 2026-09-29: env-vars (the CLAUDE_CODE_SUBPROCESS_ENV_SCRUB row does not mention the placeholders), sandboxing (troubleshooting: 0-byte read-only placeholders removed after each command), errors ("Stale sandbox mask files left by a killed session"), agent-view, cross-session-messaging, cli-reference; the installed 2.1.284 binary (sandbox startup: fixed list of paths opened in append mode, and /tmp/inline-comments-buffer.jsonl).
  • openai/codex at rust-v0.157.1 (installed) and rust-v0.158.0 (newest stable, 2026-09-28): codex-rs/tui/src/chatwidget/notifications.rs, codex-rs/tui/src/notifications/mod.rs, codex-rs/tui/src/terminal_palette.rs (identical between the tags) and the Notifications, terminal_title, notification_method, notification_condition definitions in codex-rs/config/src/types.rs (identical).
  • microsoft/terminal releases and doc/cascadia/profiles.schema.json BellStyle enum at v1.24.11911.0, v1.25.1912.0 and main (the two toast signals of the decision record are unchanged); wsl.exe --help (WSL 2.7.13.0: --exec, --cd, --shell-type).
  • Candidate notifiers and multiplexers: every pin recorded in the decision is unchanged (repository heads equal the pins; none archived).
  • No code was written where a maintained upstream exists: the hand-off is the distro convention, no upstream reproduction or cleanup tool was published, and the scripts under evidence/artifacts/ are measurement tools for this record's claims, not product code.

Evidence-class table

Claim Evidence class Command / receipt
A login shell started as the profiles start it finds no claude, codex or rtk while the empty file exists, and finds them once that one file is removed native_proven (before and after, coordinator's own output recorded as values) receipt login-shell-contract-20260929, data.incident_observation
CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 creates an empty ~/.bash_profile and takes ~/.local/bin out of the login PATH; without it no empty placeholder file is created; a real hand-off file stays byte-identical and keeps the PATH native_proven (installed client and bubblewrap in an isolated home, no-variable control arm) receipt data.isolated_reproduction; scrub_placeholder_probe.py
The installed claude doctor does not flag the scrub-created ~/.bash_profile native_proven (isolated home) receipt data.isolated_reproduction.arms[].native_doctor
The reproduction touched nothing outside its throwaway homes except the client's own state and one shared temp file, both removed native_proven (the script checks the real home's placeholder names before and after) receipt data.isolated_reproduction
The doctor's login-shell-path check fails the incident, an empty ~/.bash_login and a home with no startup file, and passes a healthy home and the hand-off file; the real host passes synthetic (five temporary homes) plus native_proven (real host) receipt data.doctor_check_controls; login_shell_check_controls.py --real-host
Creating the hand-off file changes nothing about the login PATH native_proven (13 entries, same SHA-256 prefix) receipt data.hand_off_file; login_path_digest.py
claude agents --json prints active interactive and background sessions (no token or cost field); --cwd narrows it native_proven (live snapshot of this host's sessions) receipt data.claude_agents_json_2_1_284_live_snapshot; agents_json_probe.py
The upstream landscape gives no trigger to change the terminal settings: no new Windows Terminal release, both toast signals unchanged, Claude Code 2.1.284 still newest, Codex notification, palette and kind sources identical between the installed and the newest stable tag, candidate pins unchanged source_review (GitHub API, pinned tags) receipt data.landscape_2026_09_29; landscape_refresh.py
The cause is a known upstream behaviour acknowledged by a maintainer and not yet in the environment-variable documentation source_review decision record, "What broke, and why"

Local commands run

$ python3 scripts/validate.py
exit 0: {"components": 69, "hashed_files": 8070, "profiles": 4, "receipts": 170, "status": "passed"}
$ python3 scripts/validate_foundation.py ; python3 scripts/component_matrix.py --check ; python3 scripts/new_host_grand_list.py --check
exit 0, 0 and 0
$ python3 -B evidence/artifacts/login-shell-contract-20260929/login_shell_check_controls.py --real-host
five cases as expected; real host: pass
$ python3 -B evidence/artifacts/login-shell-contract-20260929/scrub_placeholder_probe.py
no variable: 0 empty files; variable, stock home: 27 empty files including ~/.bash_profile and ~/.local/bin gone from the login PATH; variable, real hand-off file: untouched, PATH kept; real home unchanged; shared temp file removed
$ python3 -B evidence/artifacts/login-shell-contract-20260929/landscape_refresh.py
toast signals false/false and diverged/diverged; Claude Code 2.1.284; Codex notification definitions identical
$ python3 checks/check-terminal-profiles.py ; python3 nativestack.py doctor        (host practice repository)
PASS 5 profiles; doctor login-shell-path PASS (its catalog-revision DRIFT is unchanged and unrelated)

The unit-test suite was not re-run for this change: it adds no code under a tested module (documentation, a receipt and measurement scripts), and the terminal decision's PR recorded the suite's identical 321 baseline failures on this host against clean main; CI's clean runner is the authority.

Decision record

docs/decisions/2026-09-28-terminal-experience.md: "Update 2026-09-29", with the decisions table (login shell, session names, resume, agent view, telemetry gaps), each with rejected alternatives and an overturn condition.

Review

Round 1: Codex GPT-6 (read-only, max: 6 findings) and a headless Opus (max: 12 findings) returned changes-needed; all were applied. The Opus review found a real error in a first draft (a "correction" of the cooperation recipe's claude agents --json sentence was wrong: the installed CLI lists interactive sessions, so the recipe stays untouched and the decision now records the measured output). The Codex review found that the probe left a shared /tmp file and misreported non-empty directories as empty. Repairs: the probe removes the client's shared temp file and per-directory state by name and checks the real home itself, counts empty directories properly and runs the native claude doctor; the changelog filter was widened (2.1.247, 2.1.257, 2.1.271); the Codex-launcher rationale, the doctor probe wording, the receipt provenance (login_path_digest.py, the bubblewrap version) and several overclaims were corrected.
Not run: the bounded re-check of that repair. The shared Claude weekly window read 0.72 (five-hour 0.24) and the shared Codex pool 93% when it was due, and a peer session asked for no non-critical Opus work; the max-effort Opus re-check was started, stopped after about 13 minutes and produced no output. In its place every repaired script was re-run and its output is in the receipt (probe, controls, landscape, digest, agents snapshot), and validate.py passes. A later reviewer may run the re-check.

Residuals (recorded, not fixed here)

  • The reproduction stops at the API-key check: it shows the placeholders are created at startup, not what a full session or its exit does. Upstream says they persist and that cleanup at exit is being considered.
  • The hand-off file protects the name ~/.bash_profile only; a creator that truncates or replaces an existing file is not covered, and the doctor has no scheduler.
  • The Polaris distro's profiles, the agent view probe (not adopted), and the telemetry gaps (tab identity, per-skill/agent/MCP labels on metrics, project agent names shown as custom, traces, per-session dashboard, retention) are outside this change; the telemetry items wait for their owners' measurement window.
  • The doctor code is in the host practice repository, which has no remote; this change carries a copy of the check function with its controls.

Host evidence

Not applicable: no file under evidence/hosts/ is added or changed.

Checklist

  • New/changed GitHub Actions are pinned to a full commit SHA with a version comment (none added or changed).
  • New/changed workflows declare top-level permissions: contents: read (none added or changed).
  • No secrets are printed, logged or committed (gitleaks clean on the commit; the reproduction uses a non-credential dummy value); no new required secret was added.
  • No new paid hosting, subscription or billing surface was introduced.
  • Peer-owned untracked files and worktrees were preserved.

Not merged by the author unless the merge guard passes (gh pr merge --squash --match-head-commit).

🤖 Generated with Claude Code

Decides the open items of the terminal decision by research convergence and records the evidence: a scrub-mode `claude -p` probe of a
peer session left an empty ~/.bash_profile that hid ~/.profile and broke every new Windows Terminal tab (`exec: claude: not found`, exit 127);
the cause is known upstream (anthropics/claude-code #76236, #78072: the sandbox pre-creates empty placeholder files for missing protected paths
when CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 and leaves them) and is reproduced here on 2.1.284 in an isolated home with a no-variable control arm.
A real ~/.bash_profile that hands off to ~/.profile survives the reproduction byte-identical and keeps the login PATH; the practice
repository's doctor gained a login-shell-path check whose five controls behave.

Adds an "Update 2026-09-29" section to docs/decisions/2026-09-28-terminal-experience.md (what broke and why, evidence, decisions with rejected
alternatives and overturn conditions: keep `bash -lc` and a real hand-off file, no fixed session name, no resume profile, agent view not adopted,
telemetry gaps left to their owners; and a landscape refresh: no new Windows Terminal release, both toast signals unchanged, Claude Code 2.1.284
still newest, Codex rust-v0.158.0 notification, palette and kind sources identical to the installed tag), a supersession pointer on the earlier
agent-view paragraph, one bullet in recipes/claude-native-profile.md, three anti-pattern rows (this incident's, and the two of the earlier update, which
that change left out so its pull request could merge cleanly), the receipt login-shell-contract-20260929 and its scripts, and their registration in
manifests/evidence.json.

Reviewed once by Codex GPT-6 (read-only, max) and headless Opus (max): 6 and 12 findings, all applied (the probe now removes the client's shared
temp file and per-directory state and checks the real home itself, counts empty directories, runs the native `claude doctor` and records that it
does not flag the file; the changelog filter, the Codex launcher rationale, the doctor probe wording, the receipt provenance and several
overclaims were corrected). Authored by a Claude Sonnet 5.5 coordinator session.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@seathatflowsinourveins seathatflowsinourveins added the lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers label Sep 29, 2026
@seathatflowsinourveins
seathatflowsinourveins merged commit 9ad7beb into main Sep 29, 2026
25 checks passed
@seathatflowsinourveins
seathatflowsinourveins deleted the claude/login-shell-contract-20260929 branch September 29, 2026 06:41
seathatflowsinourveins pushed a commit that referenced this pull request Sep 29, 2026
…, profile example, --login-shell; repairs of the #498 re-check

Carries the terminal decision of 2026-09-28/29 in the repository so a new session or host takes it from templates and docs instead of a host edit:
- adoption/templates/claude.settings.linux-wsl2.overlay.json (preferredNotifChannel + one Notification hook that rings for a needed action only), merged
  with tools/adoption/apply_claude_settings.py; the acceptance script also checks the bell group's count and matcher, which the merge cannot see;
- [tui] notifications in the shared Codex template (needed-action kinds; decided for macOS hosts too);
- examples/claude-native/windows-terminal.fragment.example.json and the recipe's Claude profile entry (own titles, quiet explicit bell, truecolor, login shell);
- scripts/adoption_status.py --login-shell: which of ~/.bash_profile, ~/.bash_login, ~/.profile a Bash login shell reads first, from file metadata only,
  checked against the real bash over 512 startup-file combinations plus FIFO and stat-error cases;
- a Windows Terminal profiles and login shell section in adoption/platforms/linux-wsl2.md, a macOS note and a bootstrap step 4 note;
- the decision record's Repository-carried defaults section, the receipt wsl-terminal-defaults-20260929 and its acceptance scripts.

Repairs the defects two bounded reviews of the merged login-shell change (#498) and of this change found: the reproduction probe keeps the client's temp state
in a short private directory (a longer path makes the client use a fixed /tmp/cc-socks-<uid> directory) and measures the real temp dirs; the native doctor's
silence about the scrub-created file follows from its documented scope; the changelog list, the startup placeholder names and the candidate pins have producing
scripts or baselines; two anti-pattern rows are logged.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
seathatflowsinourveins added a commit that referenced this pull request Sep 29, 2026
…, profile example, --login-shell; repairs of the #498 re-check (#510)

* Terminal defaults in the repository: Claude overlay, Codex [tui] list, profile example, --login-shell; repairs of the #498 re-check

Carries the terminal decision of 2026-09-28/29 in the repository so a new session or host takes it from templates and docs instead of a host edit:
- adoption/templates/claude.settings.linux-wsl2.overlay.json (preferredNotifChannel + one Notification hook that rings for a needed action only), merged
  with tools/adoption/apply_claude_settings.py; the acceptance script also checks the bell group's count and matcher, which the merge cannot see;
- [tui] notifications in the shared Codex template (needed-action kinds; decided for macOS hosts too);
- examples/claude-native/windows-terminal.fragment.example.json and the recipe's Claude profile entry (own titles, quiet explicit bell, truecolor, login shell);
- scripts/adoption_status.py --login-shell: which of ~/.bash_profile, ~/.bash_login, ~/.profile a Bash login shell reads first, from file metadata only,
  checked against the real bash over 512 startup-file combinations plus FIFO and stat-error cases;
- a Windows Terminal profiles and login shell section in adoption/platforms/linux-wsl2.md, a macOS note and a bootstrap step 4 note;
- the decision record's Repository-carried defaults section, the receipt wsl-terminal-defaults-20260929 and its acceptance scripts.

Repairs the defects two bounded reviews of the merged login-shell change (#498) and of this change found: the reproduction probe keeps the client's temp state
in a short private directory (a longer path makes the client use a fixed /tmp/cc-socks-<uid> directory) and measures the real temp dirs; the native doctor's
silence about the scrub-created file follows from its documented scope; the changelog list, the startup placeholder names and the candidate pins have producing
scripts or baselines; two anti-pattern rows are logged.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

* Register the terminal defaults receipt, the revised login-shell receipt and the changed files' hashes (hot-file protocol)

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>

---------

Co-authored-by: Scout <[email protected]>
Co-authored-by: Claude Sonnet 5.5 <[email protected]>
seathatflowsinourveins pushed a commit that referenced this pull request Sep 30, 2026
…ough the packaged Codex lane on OmniRoute), 46 findings checked, 39 repaired

Nine read-only jobs (#484, #498, #510, #519; two lenses each, #519 in three parts) returned 46 findings (3 high, 34 medium, 9 low). Each was graded by an independent Claude verifier
(23: 17 confirmed, 4 partly, 2 refuted) or checked by the coordinator against the code or the upstream source before any change; 39 led to a repair, 2 were refuted, 3 concerned the removed
second-distro target, 2 duplicates of one convention were kept.

Repairs, each with a control that fails without it: the settings-swap tool installs only over the bytes it read, refuses keys beyond matcher and hooks and prints no matcher value (24 controls,
15 mutant runs); the notification-type scan resolves the catalog's spread identifier instead of choosing an array by contents (eight reader tests, seven mutants); the login-shell check needs an
answer for every command and an end marker, uses type -P and lets only the first startup file bash reads shadow ~/.profile; the digest, Codex strict-config, overlay, tmux and pty probes exit
nonzero when they measured nothing (selftests, an end-to-end SIGTERM case with a negative control); the BEL counter ignores UTF-8 C1 characters like the pinned output engine; the colour counter
counts SGR only; the 512-combination bash oracle compares first_read; the practice repository's sound rule is exact.

Wording corrected: tmux has a sync feature (measured); the bell icon clears after about 2 s on a focused tab; the push presence rule is for a local session; a profiles.defaults key beats a
fragment-only profile; a terminal's permission notification is timed by inactivity (the fixed-delay timer is the Agent SDK path, which the coordinator's own earlier correction had confused).

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
seathatflowsinourveins added a commit that referenced this pull request Sep 30, 2026
… (gpt-6.1-sol and gpt-6-astra-ultra through the packaged Codex lane on OmniRoute) (#532)

Nine read-only jobs of the packaged Codex lane (gpt-6.1-sol, effort max, through the local OmniRoute gateway) reviewed the four merged terminal-lane pull requests (#484, #498, #510, #519)
and returned 46 findings; each was graded by an independent Claude verifier or checked against the code or the upstream source before any change (39 repaired, 2 refuted, 3 removed with the
second-distro target, 2 kept). A bounded re-check of those repairs (three gpt-6.1-sol jobs and one gpt-6-astra-ultra job) returned 33 more findings (19 graded: 16 confirmed, 3 partly), all repaired in a
fifth round: a false recovery claim in the settings-swap tool, signal handling that still left the client behind (first signal wins, deferred cleanups, client created under a spawn flag, a mutant
runner that shows each case failing without its guard), controls that could not fail, two claims without a recorded rerun. Adds the sanitized review record, a receipt with the re-check data, a correction
note in the four older receipts and native reruns of the scrub probe and the PATH digest.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

lane:foundation Foundation lane: Claude/Codex setup, hosts, memory, RAG, research, workers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant