You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hooks run without a shell; linked project config is named
Both hooks now start node directly, a config refused for being behind a link is named at session start, and a config write that cannot rename no longer overwrites the file in place.
Fixed
Both hook entries now use the exec form.hooks/hooks.json ran the conductor as one shell string, node "${CLAUDE_PLUGIN_ROOT}/hooks/coaltipple-conductor.js". Each entry is now command: "node" with the conductor path in args, no shell and no onFailure. The args form needs Claude Code 2.1.139 or later. This answers Claude Code 2.1.299, whose changelog reads "Windows: Fixed PreToolUse and PermissionRequest hooks that set no shell failing open when Git for Windows isn't installed; a guard that fails now blocks the call". CoalTipple's hooks are SessionStart and UserPromptSubmit, not PreToolUse, so nothing here was a guard that could block a call. Why the change is made: the exec form is the vendor's recommendation, and from 2.1.299 a hook that sets no shell and cannot start fails closed on Windows without Git for Windows. The mechanism for this room is unverified: the worry was that the old string went to PowerShell with ${CLAUDE_PLUGIN_ROOT} unexpanded, so node got no script and the conductor did not run (no routing contract, and a visible hook error), but the vendor's hooks reference says the placeholders are substituted in both forms, so whether the shell ever received the placeholder is not known. CoalWash's probe handed PowerShell the literal string; Claude Code's own no-Git fallback was not run on this box. — test: scripts/lib/hooks-exec-form.test.mjs
A rename that Windows refuses no longer falls back to writing in place.configure.mjs and install.mjs write the config, and install.mjs writes the global model ranking, through a temp file and a rename. On Windows, when another program holds the file open or it is read-only, the rename fails with EPERM or EBUSY; v1.7.2 and earlier then overwrote the live file in place (the config write, and the same fallback in the ranking write), which a crash could leave half written. The rename is now retried up to five times, about 40 ms apart, and then the command fails with an error that names the file, says it is unchanged and says it is held open by another program or read-only, to close the program or clear the read-only attribute; any other error code fails at once. The shipped plugin writes neither file, so only the user-run scripts change. — test: scripts/lib/config-load.test.mjs (config), scripts/lib/classify.test.mjs (ranking)
Changed
SessionStart now names a project config it refused to read. Since v1.7.2 a config behind a link, a junction or a differently cased folder is skipped as if absent, with no word. Now one line per such file, once at session start and never on a prompt: [CoalTipple] REFUSED: <path relative to the project> resolves outside this project's own folder (a link, a junction or a differently cased name); it was not read -- replace it with a regular file at .claude/coal/coaltipple.json. The file is still not read. — test: scripts/lib/project-links.test.mjs
Hyphenated spellings of the hot keywords now fire the same hints. The conductor reads the raw line before a slash command expands, so /security-review reached it only as the hyphenated name and fired nothing, while the typed words "security review" fire the grade-4 hint. Added race-condition (grade 5), and auth-bypass, sql-injection, access-control, schema-change, rate-limit, bug-scan, security-audit, security-review, vulnerability-scan and code-audit (grade 4). It is a wider match for words already listed, not a new capability. — test: scripts/lib/conductor.test.mjs
SKILL.md tells the agent to check the real path before the writes only it can make. Before it persists fableConsent into the project config or writes proposed/ or state.json, the agent is told to check that the target, and the folders above it inside the project, are not a link or junction, and to refuse and tell the user which path if one is. This is an instruction to the model: no code enforces it, so it is a mitigation at prose strength and the residual named in v1.7.2 stands. — test: none (prose for the model; no test can enforce it)
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Hooks run without a shell; linked project config is named
Both hooks now start
nodedirectly, a config refused for being behind a link is named at session start, and a config write that cannot rename no longer overwrites the file in place.Fixed
hooks/hooks.jsonran the conductor as one shell string,node "${CLAUDE_PLUGIN_ROOT}/hooks/coaltipple-conductor.js". Each entry is nowcommand: "node"with the conductor path inargs, no shell and noonFailure. Theargsform needs Claude Code 2.1.139 or later. This answers Claude Code 2.1.299, whose changelog reads "Windows: Fixed PreToolUse and PermissionRequest hooks that set no shell failing open when Git for Windows isn't installed; a guard that fails now blocks the call". CoalTipple's hooks are SessionStart and UserPromptSubmit, not PreToolUse, so nothing here was a guard that could block a call. Why the change is made: the exec form is the vendor's recommendation, and from 2.1.299 a hook that sets no shell and cannot start fails closed on Windows without Git for Windows. The mechanism for this room is unverified: the worry was that the old string went to PowerShell with${CLAUDE_PLUGIN_ROOT}unexpanded, so node got no script and the conductor did not run (no routing contract, and a visible hook error), but the vendor's hooks reference says the placeholders are substituted in both forms, so whether the shell ever received the placeholder is not known. CoalWash's probe handed PowerShell the literal string; Claude Code's own no-Git fallback was not run on this box. — test:scripts/lib/hooks-exec-form.test.mjsconfigure.mjsandinstall.mjswrite the config, andinstall.mjswrites the global model ranking, through a temp file and a rename. On Windows, when another program holds the file open or it is read-only, the rename fails withEPERMorEBUSY; v1.7.2 and earlier then overwrote the live file in place (the config write, and the same fallback in the ranking write), which a crash could leave half written. The rename is now retried up to five times, about 40 ms apart, and then the command fails with an error that names the file, says it is unchanged and says it is held open by another program or read-only, to close the program or clear the read-only attribute; any other error code fails at once. The shipped plugin writes neither file, so only the user-run scripts change. — test:scripts/lib/config-load.test.mjs(config),scripts/lib/classify.test.mjs(ranking)Changed
[CoalTipple] REFUSED: <path relative to the project> resolves outside this project's own folder (a link, a junction or a differently cased name); it was not read -- replace it with a regular file at .claude/coal/coaltipple.json.The file is still not read. — test:scripts/lib/project-links.test.mjs/security-reviewreached it only as the hyphenated name and fired nothing, while the typed words "security review" fire the grade-4 hint. Addedrace-condition(grade 5), andauth-bypass,sql-injection,access-control,schema-change,rate-limit,bug-scan,security-audit,security-review,vulnerability-scanandcode-audit(grade 4). It is a wider match for words already listed, not a new capability. — test:scripts/lib/conductor.test.mjsSKILL.mdtells the agent to check the real path before the writes only it can make. Before it persistsfableConsentinto the project config or writesproposed/orstate.json, the agent is told to check that the target, and the folders above it inside the project, are not a link or junction, and to refuse and tell the user which path if one is. This is an instruction to the model: no code enforces it, so it is a mitigation at prose strength and the residual named in v1.7.2 stands. — test: none (prose for the model; no test can enforce it)Release page · CoalTipple
All reactions