Skip to content

Add SessionStart hook to provision web environment#6613

Open
masenf wants to merge 7 commits into
mainfrom
claude/unit-tests-setup-3XdNQ
Open

Add SessionStart hook to provision web environment#6613
masenf wants to merge 7 commits into
mainfrom
claude/unit-tests-setup-3XdNQ

Conversation

@masenf
Copy link
Copy Markdown
Collaborator

@masenf masenf commented Jun 5, 2026

The web container image predates this repo's current requirements, so a
fresh uv sync + test run fails out of the box. Add a SessionStart hook
(web-only) that reconciles the environment on every session start:

  • Upgrade uv from PyPI when below tool.uv.required-version (the astral.sh
    installer and uv self update are blocked / GitHub-rate-limited here).
  • Install and use stable CPython 3.14.5 instead of the image's pre-baked
    3.14 prerelease, whose typing._eval_type signature is incompatible with
    the pinned pydantic and breaks every import.
  • Fetch git tags so Reflex's VCS-derived version resolves correctly;
    otherwise it becomes 0.0.0 and trips downstream version gates such as
    reflex-hosting-cli's compatibility check.

Narrow .gitignore from the whole .claude dir to just .claude/.worktrees so
the shared hook and settings are tracked.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK

claude added 4 commits June 5, 2026 01:22
The web container image predates this repo's current requirements, so a
fresh `uv sync` + test run fails out of the box. Add a SessionStart hook
(web-only) that reconciles the environment on every session start:

- Upgrade uv from PyPI when below tool.uv.required-version (the astral.sh
  installer and `uv self update` are blocked / GitHub-rate-limited here).
- Install and use stable CPython 3.14.5 instead of the image's pre-baked
  3.14 prerelease, whose typing._eval_type signature is incompatible with
  the pinned pydantic and breaks every import.
- Fetch git tags so Reflex's VCS-derived version resolves correctly;
  otherwise it becomes 0.0.0 and trips downstream version gates such as
  reflex-hosting-cli's compatibility check.

Narrow .gitignore from the whole .claude dir to just .claude/.worktrees so
the shared hook and settings are tracked.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
Keep personal settings overrides out of version control alongside the
already-ignored .claude/.worktrees, while still tracking the shared hook
and settings.json.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
Drop the hardcoded 3.14.5 / --python flag. `uv python install` excludes
prereleases, so it fetches the stable patch matching .python-version even
when the image only has the prerelease installed; `uv sync` then prefers
that stable interpreter over the rc. The hook no longer needs updating when
the repo bumps its Python version.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
The 3.14 prerelease is not baked into the image; the image's stale uv
(built before Python 3.14.0 final) downloads it because its release
manifest only knows 3.14 release candidates. Upgrading uv first is the
real fix; `uv python install` remains a guard against reusing a prerelease
left by an earlier stale-uv sync.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
@masenf masenf requested a review from a team as a code owner June 5, 2026 02:27
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Jun 5, 2026

Merging this PR will not alter performance

✅ 28 untouched benchmarks


Comparing claude/unit-tests-setup-3XdNQ (04ecb5f) with main (9c8a0ae)

Open in CodSpeed

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 5, 2026

Greptile Summary

Adds a SessionStart hook (session-start.sh) that reconciles the Claude Code web container environment on every session start, and narrows .gitignore so the new hook and shared settings file are tracked by git.

  • session-start.sh: Upgrades uv from PyPI when below tool.uv.required-version, installs a stable CPython via uv python install, fetches git tags (shallow clone fix), and runs uv sync — all gated on CLAUDE_CODE_REMOTE=true so local dev environments are untouched.
  • .gitignore: Replaces the blanket .claude ignore with specific ignores for .claude/.worktrees and .claude/settings.local.json, allowing the hook and shared settings to be committed.

Confidence Score: 4/5

Safe to merge for its stated purpose; the script is well-commented, correctly skips non-web environments, and handles the uv/Python/tags bootstrapping problem cleanly.

The hook is narrowly scoped and the logic is sound. Two minor behavioral gaps: uv sync can hard-fail the hook in offline scenarios (unlike git fetch, which is guarded), and the PATH update to prefer ~/.local/bin/uv doesn't propagate to Claude Code's process after the hook exits. Neither is a showstopper for the hook's primary goal, but the offline fragility could make the web session unusable when the package registry is unreachable.

.claude/hooks/session-start.sh and .gitignore are the files most worth a second look.

Important Files Changed

Filename Overview
.claude/hooks/session-start.sh New SessionStart hook that upgrades uv, installs a stable CPython, fetches git tags, and runs uv sync for web container sessions; uv sync is not guarded with
.claude/settings.json New settings file registering the SessionStart hook command; straightforward and correct.
.gitignore Narrows .claude ignore from the whole directory to just .worktrees and settings.local.json; other Claude Code runtime subdirectories (cache, memory, todos) may now show as untracked for local contributors.

Reviews (1): Last reviewed commit: "Correct the Python-prerelease rationale ..." | Re-trigger Greptile

Comment thread .claude/hooks/session-start.sh Outdated
git fetch --tags --quiet || true

# 4. Install all workspace dependencies (uses .python-version).
uv sync
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 uv sync failure aborts the session in offline scenarios

git fetch --tags is guarded with || true to tolerate offline/rate-limited runs, but uv sync on the same line is not. Under set -euo pipefail, a network-isolated run that passes the git step will still hard-fail on uv sync, aborting the hook and potentially the entire session start. If the intent is to allow best-effort sync when offline (mirroring the git-fetch tolerance), consider adding || true or wrapping in an if-block that logs but doesn't abort.

Comment thread .gitignore
Comment on lines +25 to +26
.claude/.worktrees
.claude/settings.local.json
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Other .claude/ runtime artifacts may now appear as untracked

Narrowing from .claude to only .claude/.worktrees and .claude/settings.local.json means any other directories that Claude Code creates at runtime (e.g. .claude/cache/, .claude/todos/, .claude/memory/) will show up as untracked files in git status for all contributors running Claude Code locally. Consider adding a broader catch-all like .claude/* and then un-ignoring only the specific files that should be tracked (!.claude/hooks/ and !.claude/settings.json), or adding explicit ignores for each known runtime subdirectory.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +61 to +62
export PATH="$HOME/.local/bin:$PATH"
hash -r 2>/dev/null || true
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 PATH update doesn't propagate to Claude Code after the hook exits

export PATH="$HOME/.local/bin:$PATH" only affects the hook script's own subprocess. Once the script exits, Claude Code's process environment is unchanged, so any uv commands Claude Code runs after session start (e.g. uv add, uv sync triggered by tool calls) will still resolve to the old system uv, not the just-upgraded one. For this specific hook the in-script uv python install and uv sync use the right version, so the initial setup is correct — but it's worth being aware that the upgraded binary is only visible within this script's lifetime.

claude added 3 commits June 5, 2026 05:22
Replace the embedded Python version-comparison with a single idempotent
pip install of uv>=<required-version> parsed from pyproject.toml. pip is
a near-instant no-op when the constraint is already satisfied, so the
explicit version check was redundant. Also pass --root-user-action=ignore
to suppress pip's cosmetic root-user warning in the web container.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
Address review feedback:
- .gitignore: ignore __pycache__/, .pytest_cache/, .ruff_cache/ (incl.
  nested) and .mypy_cache/, the scratch dirs that test/lint runs generate.
- Persist the ~/.local/bin PATH prepend via $CLAUDE_ENV_FILE so the
  upgraded uv stays visible to the session's commands after the hook exits,
  not just within the hook process.
- Guard 'uv sync' so a transient install failure warns instead of aborting
  startup; the container still comes up and sync can be retried.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
.claude/settings.local.json and .claude/.worktrees were already ignored;
add CLAUDE.local.md (personal project memory) so user-local Claude state
isn't shared. The pattern has no slash, so it also matches nested copies
in sub-packages. Shared team files (.claude/settings.json, .claude/hooks,
CLAUDE.md) stay tracked.

https://claude.ai/code/session_014Bp9oVCfiq8DSnTK8VfozK
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants