anthropics / anthropics/claude-code

[BUG] Claude Code on the Web: a repository's .claude/settings.json is silently ignored, so its hooks never run

Đang mở
#89,215 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
area:claude-code-web area:hooks bug has repro platform:web
Ngôn ngữ chính
Python
Star
145k
Fork
23.1k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

### What's Wrong?

In a Claude Code on the Web cloud session, the session's project root is the **parent** directory of the repository checkout, not the checkout itself. Claude Code therefore never loads `/.claude/settings.json`, and any hooks registered there never fire. Nothing warns — not the session, not the logs.

This contradicts the documented contract in [Configure cloud environments](https://code.claude.com/docs/en/cloud-environments), which:

- lists "Your repo's `.claude/settings.json` hooks" as carrying over to a cloud session — *"Yes — part of the clone"*
- tells users to *"add a SessionStart hook to your repo's `.claude/settings.json`"* for dependency installation
- states that *"`$CLAUDE_PROJECT_DIR` resolves to the repository root, so the hook finds the script regardless of the session's working directory"* — while in our sessions `$CLAUDE_PROJECT_DIR` was **empty**

**Likely trigger (hypothesis, untested):** our environment attaches **two** repositories. The documentation describes the single-repository case, where the project root is the checkout. With two attached repositories the project root appears to become their common parent, `/home/user`. A single-repository session may well behave as documented; we did not test one.

**Impact.** Repositories that use a `SessionStart` hook to finish environment setup (install a toolchain, hydrate Git LFS, initialize submodules) start every cloud session with that work undone, then fail at the first build or test — minutes into the conversation, far from the cause.

**Why it is hard to diagnose from inside a session:**

- A silently ignored settings file looks identical to a hook that ran and did nothing.
- The launcher's own `SessionStart` hook (`session-start-git-identity.sh`, from `/root/.claude/launcher-settings.json`) supplies a decoy signal in the diagnostic log with a plausible exit code and duration, so the failure reads as "the repo's hook ran and exited cleanly."
- Hook stdout never reaches the session's context ([#10373](https://github.com/anthropics/claude-code/issues/10373)), so a hook made deliberately loud is still invisible to the agent.
- `CLAUDE.md` **is** loaded from the checkout, including its `@`-imports — so file discovery reaches the subdirectory while settings loading does not, which actively suggests the repo is being treated as the project.

It took four cloud test-session rounds to locate this; two intermediate rounds produced fixes for a misdiagnosis, because every in-session signal pointed at the hook's own logic rather than at registration.

### What Should Happen?

Either `.claude/settings.json` is loaded from each attached repository's checkout, or Claude Code says it is skipping it. A silent skip of a version-controlled configuration file is the core problem; the hook is only the most visible casualty.

Suggested fixes, in order of preference:

1. Load `.claude/settings.json` from each attached repository's checkout.
2. If that is not intended, emit a warning naming the path that was skipped and the project root that was used.
3. Document the project-root behaviour for multi-repository cloud sessions, and provide a supported way to register a `SessionStart` hook that belongs to a repository.

### Error Messages/Logs

There is no error. That is the defect. The only `SessionStart` evidence in the diagnostic log belongs to the launcher's own hook:

```json
{"timestamp":"2026-08-24T11:42:09.499Z","level":"info","event":"hook_spawn_started","data":{"hook_event_name":"SessionStart","index":0}}
{"timestamp":"2026-08-24T11:42:09.508Z","level":"info","event":"hook_spawn_completed","data":{"hook_event_name":"SessionStart","index":0,"duration_ms":15,"exit_code":0,"aborted":false}}
```

Environment observations from the session:

```
$ ls /root/.claude/projects/ # exactly one project: the parent, not the checkout
-home-user

$ ls /home/user/.claude/ # does not exist
ls: cannot access '/home/user/.claude/': No such file or directory

$ echo "[${CLAUDE_PROJECT_DIR:-}]" # empty in the hook process
[]
$ echo "$CLAUDE_CODE_REMOTE"
true
$ echo "$PWD" ; echo "$HOME"
/home/user/
/root
```

The repo's own hook never appears in any log, and its script never executes (verified by it writing a file on every branch, including its early-exit branch — the file is never created).

### Steps to Reproduce

1. Create a cloud environment with **two attached repositories**.
2. In one repository, commit `.claude/settings.json` registering a `SessionStart` hook that proves it ran, e.g.:

```json
{
"hooks": {
"SessionStart": [
{ "hooks": [ { "type": "command", "command": "date > /tmp/hook-ran.log" } ] }
]
}
}
```

3. Start a new cloud session on that repository.
4. Check `/tmp/hook-ran.log` — it does not exist. Check `ls /root/.claude/projects/`, which shows a single project entry for `/home/user`, the parent of the checkout.

The hook is never registered because `/home/user//.claude/settings.json` is one level below the project root. A hook with an explicit `"matcher": "startup|resume"` behaves the same; we later registered the identical hook entry into `~/.claude/settings.json` and `/home/user/.claude/settings.json` from the environment's setup script, and it then fired on every session — so the hook definition itself was always valid.

### Related issues

- [#33815](https://github.com/anthropics/claude-code/issues/33815) (closed): `$CLAUDE_PROJECT_DIR` empty/unset in hook execution. We observe the same emptiness in cloud sessions, which is why the workaround below cannot rely on it.
- [#10373](https://github.com/anthropics/claude-code/issues/10373) (open): `SessionStart` hook stdout never processed for brand-new conversations. Compounds this bug — a hook made deliberately loud is still invisible to the session. We have added a cloud-session confirmation there rather than duplicating it here.
- [#19134](https://github.com/anthropics/claude-code/issues/19134) (closed as stale): documents the same repo-level `SessionStart` hook pattern for cloud dependency management — the pattern this bug silently breaks.

### Workaround, for anyone else hitting this

Have the environment's setup script (which runs at snapshot-build time, as root) merge the hook registration into the settings a session actually reads — `$HOME/.claude/settings.json` and `/.claude/settings.json` — preserving any existing content so the launcher's own hooks survive. Confirmed working: the hook then fires on every session.

### Claude Code Version

Unknown — Claude Code on the Web cloud session, observed 2026-08-24. The cloud environment provisions its own Claude Code build; no version string is surfaced in the session.

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Hướng nghiên cứu

Start by reproducing the two-attached-repository setup and inspect how the cloud session chooses its project root and loads .claude/settings.json. Compare the repository hook with the working registration in ~/.claude/settings.json, and check the project and hook diagnostics described in the issue. Done means repository settings are loaded, or a clear warning and supported registration path explains when they are skipped.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
json
Lĩnh vực
cloud, devtools
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Sôi nổi
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
42/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.