the repo carries no Claude Code settings (#23)

A committed .claude/settings.json bound everyone who opens the repo in Claude Code: it switched
their auto memory off, and its one hook guarded the install against Claude's Edit and Write
tools only, never a write through the shell or by another agent. The rule it backed is enforced
for every tool by the code and by scripts/smoke.sh's install watch, which METHOD now cites. jq is
no longer a prerequisite, and .gitignore shares only the skills under .claude/.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sam Sung
2026-09-24 08:40:49 +07:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 6520b76995
commit 8866fe3c91
5 changed files with 4 additions and 82 deletions
-56
View File
@@ -1,56 +0,0 @@
#!/usr/bin/env bash
# PreToolUse(Edit|Write|NotebookEdit) guard: refuse to write anything into the 1.12.1 install.
#
# Reads the hook JSON on stdin; exit 2 blocks the call, with stderr as the reason. The protected
# roots are WOW_DATA and the `WoW` link of the primary checkout and of the cwd.
# BENILLA_ALLOW_INSTALL_WRITE=1 lets a write through.
input=$(cat)
path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // .tool_input.notebook_path // empty' 2>/dev/null)
[ -n "$path" ] || exit 0
cwd=$(printf '%s' "$input" | jq -r '.cwd // empty' 2>/dev/null)
cwd="${cwd:-$PWD}"
case "$path" in
/*) ;;
'~'/*) path="${HOME}${path#\~}" ;;
*) path="$cwd/$path" ;;
esac
[ -n "${BENILLA_ALLOW_INSTALL_WRITE:-}" ] && exit 0
# Resolve the target through its nearest existing ancestor: a Write may name new directories too.
dir=$(dirname "$path")
while [ ! -d "$dir" ] && [ "$dir" != "/" ] && [ "$dir" != "." ]; do dir=$(dirname "$dir"); done
[ -d "$dir" ] || exit 0
real=$(cd -P "$dir" 2>/dev/null && pwd) || exit 0
# Compare physical paths (`cd -P`): `WoW` may be a symlink, and a write can name either spelling.
own=$(git -C "$(dirname "$0")" rev-parse --path-format=absolute --git-common-dir 2>/dev/null)
primary=$(cd "${own:-.}/.." 2>/dev/null && pwd)
for root in "${WOW_DATA:-}" "$primary/WoW" "$cwd/WoW"; do
[ -n "$root" ] && [ -d "$root" ] || continue
root=$(cd -P "$root" 2>/dev/null && pwd) || continue
case "$real/" in
"$root"/*)
cat >&2 <<EOF
BLOCKED: that write targets the 1.12.1 INSTALL ($root).
the file: $path
benilla reads a WoW install and never writes to one (docs/METHOD.md). It is the player's own copy
of somebody else's game, and the repo may never contain any of it.
Where the thing you are writing actually goes:
· anything the client persists → \`crate::local_state\` (\`benilla-config/\`)
· a capture, log, or scratch file → the session scratchpad
· a doc → the repo
A deliberate exception is \`BENILLA_ALLOW_INSTALL_WRITE=1\`.
EOF
exit 2
;;
esac
done
exit 0
-17
View File
@@ -1,17 +0,0 @@
{
"autoMemoryEnabled": false,
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|NotebookEdit",
"hooks": [
{
"type": "command",
"command": "\"${CLAUDE_PROJECT_DIR}/.claude/hooks/guard-wow-install.sh\"",
"timeout": 10
}
]
}
]
}
}
+2 -5
View File
@@ -32,13 +32,10 @@ trace-*.json
.DS_Store
*.swp
/.idea/
# Claude Code: share the project hooks + settings + slash commands + skills, ignore per-machine state.
# Claude Code: the skills are shared procedures (AGENTS.md names them); every other file under
# .claude/ is its owner's own settings.
/.claude/*
!/.claude/settings.json
!/.claude/hooks/
!/.claude/commands/
!/.claude/skills/
/.claude/settings.local.json
# Python bytecode from the `scripts/` tooling.
__pycache__/
+1 -1
View File
@@ -39,7 +39,7 @@ fork, and forks are welcome.
- **The toolchain.** Stable Rust (`rust-toolchain.toml` adds clippy and rustfmt) and a C
compiler, because the client's Lua is vendored and built from source. On macOS the Xcode
command line tools, which also supply libclang for the audio bindings; on Linux the ALSA and
udev development packages and pkg-config. `python3` runs two of the gates, and `jq` the hooks.
udev development packages and pkg-config. `python3` runs two of the gates.
- **A 1.12.1 install of your own.** `WOW_DATA=<its Data folder>`, or a `WoW` link at the repo
root, which only a dev build sees: the player build looks for `Data/` or `WoW/Data/` beside
the binary. benilla reads the install and never writes into it. `WOW_DATA=` (set, empty)
+1 -3
View File
@@ -40,8 +40,7 @@ comment naming the reference fact and why we differ. Anything else is a fork.
interface code: FrameXML and GlueXML run off the player's own patch chain, and our own
counterparts under `assets/ui` stay until they retire.
- **The install is read-only.** benilla never writes into the WoW folder: no screenshot, log,
cache or scratch file. A hook blocks such a write at the tool call, and `scripts/smoke.sh`
fails a run that leaves the install changed.
cache or scratch file. `scripts/smoke.sh` fails a run that leaves the install changed.
- **Local state lives in one folder**, `benilla-config/` beside the binary, and every path to
it resolves through `crate::local_state`. Player settings are CVars persisted as a diff in
`benilla-config/config.toml`.
@@ -85,7 +84,6 @@ comment naming the reference fact and why we differ. Anything else is a fork.
- **Platform seams**: a `cfg(target_os)`, a `[target.'cfg(…)']` dependency, a `#[link]` or an
`extern "system"` is invisible to the gates of the platform you are on. Say in the commit
which platforms you built.
- One hook: no writes into the install. Everything else is a gate or discipline.
## The local server