Skip to content

Make the cloud SessionStart hook async; fix MariaDB test auth - #67

Merged
soham2008xyz merged 3 commits into
mainfrom
claude/fix-session-start-hook
Nov 2, 2026
Merged

soham2008xyz merged 3 commits into
mainfrom
claude/fix-session-start-hook

Conversation

@renderbit-technologies

Copy link
Copy Markdown
Owner

Description

Claude Code cloud sessions on this repo seemed to "never start working": the initial prompt and follow-up messages never became a turn. The cause is the synchronous SessionStart hook, which held the first turn for about 10 minutes, with a timeout of up to 30 minutes.

Root cause (with evidence)

  • composer install --prefer-dist tries to download all 43 packages as GitHub archives. The cloud session's GitHub proxy rejects every one with HTTP 403: "GitHub access to this repository is not enabled for this session". That applies to api.github.com/repos/*/zipball/*, codeload.github.com/* and github.com/*/archive/* for any repo not attached to the session, i.e. every third-party package. Composer reports this as Could not authenticate against github.com and falls back to sequential git clones.

  • Measured on a fresh container:

    Step Time
    Original hook, end to end 10m16s (exit 0)
    ↳ composer install --prefer-dist (all 43 dists 403 → git source) ~10m
    ↳ npm install (registry.npmjs.org bypasses the proxy) 5s
    ↳ apt-get install mariadb-server + start ~20s
    Cold composer install --prefer-source, empty cache 9m18s

    Nearly all the time goes into the git clones themselves, so no Composer flag can make a cold install fast here. The only real fix is to stop blocking the session on it. In the child sessions, the proxy's curl error 28 … Proxy CONNECT aborted due to timeout retries added more time on top.

  • set -euo pipefail did not abort startup in my run (exit 0). Even if it had, a failed hook doesn't block the session; the delay came from the hook running so long.

Second bug found: PHPUnit couldn't connect to the DB

The hook checks whether root's password is set with mysql -uroot -proot … over the Unix socket. MariaDB's default unix_socket auth lets OS root in with any password, so that check always passed and the ALTER USER never ran. PHPUnit connects over TCP (127.0.0.1:3306) and failed with Error establishing a database connection / Access denied for user 'root'@'localhost'.

Changes

  • .claude/hooks/session-env.sh (new, sync, ~0s): writes WP_TESTS_DB_* and PATH to $CLAUDE_ENV_FILE.
  • .claude/hooks/session-start.sh now runs async ({"async": true, "asyncTimeout": 1800000}), so the first turn starts immediately:
    • It logs each step and its duration to /tmp/rfsd-session-setup.log, and writes /tmp/rfsd-session-setup.done on success.
    • Each step tolerates failure: a failed step is recorded, the remaining steps still run, and the script exits 1 at the end.
    • It skips Composer and npm when the lockfiles, manifests and the script itself haven't changed (hash files kept in vendor/ and node_modules/, both git-ignored).
    • It runs the quick npm and MariaDB steps before the slow Composer step.
    • It uses --prefer-source, because GitHub dist downloads always 403 in cloud sessions.
    • It checks the MariaDB password over TCP, and sets unix_socket OR mysql_native_password so socket access keeps working.
  • .claude/settings.json: registers both hooks; the hook timeouts drop from 1800s to 30s and 60s.
  • CLAUDE.md: tells agents to wait for the .done marker instead of running composer install themselves.

Related Issue

None.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Chore (maintenance, refactoring, or other non-user-facing changes)

Checklist

  • My code follows the project's code style and conventions
  • I have tested my changes thoroughly
  • I have updated documentation where needed
  • All existing tests pass (if applicable)
  • Changes do not introduce security issues

Testing Instructions

Results in a cloud container:

  • Cold run (fresh worktree, empty Composer cache): hook printed the async marker and completed in the background in 8m55s, exit 0 (Composer 532s, npm 4s, MariaDB 0s since it was already installed). vendor/bin/phpcs -i lists WordPress, WordPress-Core, WordPress-Docs, WordPress-Extra.
  • Warm run with unchanged lockfiles: 0.03s. Changing package.json reruns npm.
  • vendor/bin/phpcs includes/coverage.php: clean.
  • vendor/bin/phpunit: OK (306 tests, 865 assertions). Before this change it failed with the DB auth error.
  • npx jest: 31 passed.

To reproduce: CLAUDE_CODE_REMOTE=true CLAUDE_PROJECT_DIR=$PWD .claude/hooks/session-start.sh; tail -f /tmp/rfsd-session-setup.log

Additional Notes

Trade-off of async: during the first ~10 minutes of a fresh session, phpcs/phpunit aren't available yet. CLAUDE.md now tells the agent to check /tmp/rfsd-session-setup.done first.

Optional environment change (only the repo owner can make it). To make dependencies ready from the very first minute, add the installs to the cloud environment's Setup script: open the cloud environment menu in the session's title bar → Edit → Setup script. The script starts one directory above the repo:

cd renderbit-faq-structured-data-wordpress-plugin
COMPOSER_ALLOW_SUPERUSER=1 composer install --no-interaction --no-progress --prefer-source
npm install --no-audit --no-fund
DEBIAN_FRONTEND=noninteractive apt-get update -qq && apt-get install -y -qq mariadb-server

The hook then finds everything up to date and finishes in seconds. Changing the network allowlist won't help: the 403s come from the session's per-repository GitHub access policy, not from a blocked host.


Generated by Claude Code

Cloud sessions sat at their first turn for ~10 minutes because the
synchronous SessionStart hook ran a cold `composer install`. The session's
GitHub proxy refuses archive downloads (api.github.com zipball, codeload)
with 403 for repos not attached to the session, so all 43 Composer
packages fell back to sequential git clones.

- Split the hook: session-env.sh (sync, instant) writes the test DB env
  vars and PATH; session-start.sh runs async and logs to
  /tmp/rfsd-session-setup.log, writing /tmp/rfsd-session-setup.done on success.
- Skip composer/npm when composer.lock/package-lock.json are unchanged.
- Use --prefer-source since dist downloads from GitHub always 403 here.
- Each step is logged with its duration; one failure no longer stops the rest.
- Fix the MariaDB password check: over the Unix socket, unix_socket auth
  lets OS root in with any password, so the password was never set and
  PHPUnit (TCP 127.0.0.1) got "Access denied". Check over TCP instead.
- Document the background setup in CLAUDE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016QZq4ts3V2N5nh2sZeUHm2
@codacy-production

codacy-production Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@soham2008xyz
soham2008xyz marked this pull request as ready for review November 2, 2026 09:10
@soham2008xyz
soham2008xyz requested a balanced review from Copilot November 2, 2026 09:10
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T09:12:38.885681Z 3d4690b Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Codacy (Agentlinter) flagged the 45-word sentence as overly complex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016QZq4ts3V2N5nh2sZeUHm2

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Needs a closer look

The DevOps hook's async-hook detach semantics and MariaDB TCP-to-localhost auth resolution are beyond static review and depend on the author's cloud-session test evidence to confirm.

No open issues 🎉

What changed in this PR

This PR fixes two problems that prevented Claude Code cloud sessions on this repo from starting work: (1) the SessionStart hook ran synchronously and blocked the first turn for ~10 minutes while Composer git-cloned every dependency (dist archives 403 behind the session's GitHub proxy), and (2) the MariaDB root-password check ran over the Unix socket where unix_socket auth masked the missing password, so PHPUnit's TCP connection kept failing with "Access denied". The change splits the hook into a fast synchronous env-writer and an async installer, and repairs the DB auth check. This is dev-tooling only — no runtime plugin code is touched.

Changes:

  • Make session-start.sh run async (emits {"async": true, "asyncTimeout": 1800000}), with per-step failure tolerance, duration logging to /tmp/rfsd-session-setup.log, a /tmp/rfsd-session-setup.done marker, hash-based skip of unchanged installs, and --prefer-source for Composer.
  • Add synchronous session-env.sh to write WP_TESTS_DB_* and PATH instantly, and register it in .claude/settings.json (timeouts reduced to 30s/60s).
  • Fix the MariaDB check to use TCP (-h127.0.0.1) and set unix_socket OR mysql_native_password; document the async setup/wait-for-marker flow in CLAUDE.md.

I reviewed the shell logic (empty-array handling under set -u, the set -e removal with the tolerant step wrapper, hash-skip paths, and the MariaDB idempotency/auth path), confirmed both scripts pass bash -n, the new hook is executable, referenced lockfiles exist, and vendor//node_modules/ are git-ignored with /.claude already export-ignore. No blocking issues found. The duplicated DB credentials across session-env.sh and session-start.sh are a minor drift risk but are explicitly cross-referenced with "must match" comments, which is a reasonable mitigation for a hook that must stay fast and standalone.

File Description
.claude/​hooks/​session-start.sh Reworked to run async with failure-tolerant steps, duration logging, done-marker, hash-based install skipping, --prefer-source, and a TCP-based MariaDB auth check.
.claude/​hooks/​session-env.sh New synchronous hook writing static WP_TESTS_DB_* and PATH env vars so tests work before the async installs finish.
.claude/​settings.json Registers the new env hook and lowers hook timeouts (1800s → 30s/60s).
CLAUDE.md Documents the background setup, the .done marker to wait on, and not to run composer install manually.

Review effort: Balanced

@soham2008xyz
soham2008xyz merged commit 28d227f into main Nov 2, 2026
17 checks passed
@soham2008xyz
soham2008xyz deleted the claude/fix-session-start-hook branch November 2, 2026 09:20
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.

4 participants