mirror of
https://github.com/OthmanAdi/planning-with-files.git
synced 2026-09-14 16:09:40 +08:00
eb8af2f02f
closes #239, reported by Raymond Manaloto (@sortakool) The progress reminder is addressed to Claude: [planning-with-files] Update progress.md with what you just did. ... hooks/claude-hook.sh emitted it as systemMessage, which Claude Code documents as a warning shown to the USER. So the person saw the instruction after every Write, Edit and Bash call for a whole session, and the model it is written for never saw it once. emit_session_start eleven lines above already emitted hookSpecificOutput.additionalContext for its own event, so the correct shape was in the same file the whole time. .codex/hooks/post_tool_use.py had the identical defect, next to a pre_tool_use.py and a run_sh.py that already used the right shape. Three defects, one line apart, fixed together: 1. The field. Both routes now emit additionalContext under hookSpecificOutput with "hookEventName": "PostToolUse". 2. The throttle. Once per turn rather than once per tool call. The string is a constant, so every repeat after the first carries no information: it names no tool, no file and no phase. UserPromptSubmit and SessionStart fire once per turn and clear a marker; the first post-tool fire of the turn sets it. The marker lives in the user's private cache under pwf-turn/, never in the plan directory, and is keyed on the plan path plus PWF_SESSION_ID so two sessions sharing a plan do not silence each other. A cache root that cannot be created skips the throttle rather than the reminder, so a broken cache cannot quietly remove the signal instead of the noise. 3. The matcher. Bash comes off PostToolUse on all three manifests: ls, git status and grep were tripping a "you changed something, record it" nudge. hooks/hooks.json goes to Write|Edit and both Codex manifests to apply_patch|Edit|Write. PreToolUse keeps Bash, because a plan reminder before a shell command is a different and wanted behaviour. The standalone skill route already used Write|Edit, which is further evidence the wider matchers were drift rather than intent. Fixing this surfaced a fourth thing. active_plan_dir() in hooks/claude-hook.sh resolves through the shared resolver and then fell back to the legacy root task_plan.md: the #237 fallback removed from the script and Codex routes in v3.15.0 and missed on the plugin dispatcher. A rejected PLAN_ID or PWF_PLAN_ROOT now stops there too. Deliberately not in this change: FileChanged, which would catch a Bash command that rewrites a file, is a new event surface with its own behaviour and belongs in a release where it can be tested on its own. The standalone skill route still emits the sentence as plain stdout from a YAML frontmatter scalar with no throttle; it already carries the narrow matcher so the volume reported here never applied to it, and giving it the throttle means either putting cache-key logic inside a hook scalar or routing it through a new script context across eleven SKILL.md files. Tests: 10 in tests/test_post_tool_nudge.py, driving both routes as processes rather than asserting on source. One proves the two Codex scripts agree on the marker key by asserting the re-arm deletes the exact file the throttle wrote: they derive it independently and one resolves a PWF_PLAN_ROOT pin while the other does not, so a divergence would leave the nudge firing once per session with nothing in any log.
92 lines
4.1 KiB
JSON
92 lines
4.1 KiB
JSON
{
|
|
"description": "Codex lifecycle hooks for planning-with-files plugin installs",
|
|
"hooks": {
|
|
"SessionStart": [
|
|
{
|
|
"matcher": "startup|resume|clear|compact",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/run_sh.py\" session-start.sh",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA==",
|
|
"statusMessage": "Loading planning context"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"UserPromptSubmit": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/run_sh.py\" user-prompt-submit.sh",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA=="
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash|apply_patch|Edit|Write",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/pre_tool_use.py\"",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA==",
|
|
"statusMessage": "Checking plan before tool use"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PermissionRequest": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/permission_request.py\"",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA=="
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PostToolUse": [
|
|
{
|
|
"matcher": "apply_patch|Edit|Write",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/post_tool_use.py\"",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA==",
|
|
"statusMessage": "Reviewing changes against plan"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"PreCompact": [
|
|
{
|
|
"matcher": "*",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/run_sh.py\" pre-compact.sh",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA==",
|
|
"statusMessage": "Preparing planning context before compact"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"Stop": [
|
|
{
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"${PLUGIN_ROOT}/.codex/hooks/stop.py\"",
|
|
"commandWindows": "powershell.exe -NoLogo -NoProfile -NonInteractive -EncodedCommand JgAgACgASgBvAGkAbgAtAFAAYQB0AGgAIAAkAGUAbgB2ADoAUABMAFUARwBJAE4AXwBSAE8ATwBUACAAJwAuAGMAbwBkAGUAeABcAGgAbwBvAGsAcwBcAHAAdwBmAC0AaABvAG8AawAuAGMAbQBkACcAKQAgAHAAbAB1AGcAaQBuAF8AZABpAHMAcABhAHQAYwBoAC4AcAB5AA==",
|
|
"timeout": 30
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|