Skip to content

Commit 7b14e64

Browse files
committed
Add per-hook disable mechanism for plugin hooks
Hooks now check .codeforge/config/disabled-hooks.json at startup and exit early if their script name appears in the disabled list. Disables git-state-injector, ticket-linker, spec-reminder, and commit-reminder by default. Also comments out legacy claude-session-dashboard feature in devcontainer.json (replaced by first-party dashboard). Fixed misplaced hook gate in syntax-validator.py (was inside try block).
1 parent ea386a6 commit 7b14e64

File tree

28 files changed

+194
-6
lines changed

28 files changed

+194
-6
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"disabled": [
3+
"git-state-injector",
4+
"ticket-linker",
5+
"spec-reminder",
6+
"commit-reminder"
7+
]
8+
}

container/.codeforge/file-manifest.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,5 +60,11 @@
6060
"destFilename": "settings.template.json",
6161
"enabled": true,
6262
"overwrite": "always"
63+
},
64+
{
65+
"src": "config/disabled-hooks.json",
66+
"dest": "${CLAUDE_CONFIG_DIR}",
67+
"enabled": false,
68+
"overwrite": "never"
6369
}
6470
]

container/.devcontainer/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Hooks
6+
- **Per-hook disable mechanism** — add script names to `.codeforge/config/disabled-hooks.json` to disable individual hooks without disabling the entire plugin. Takes effect immediately, no restart needed.
7+
- Disabled by default: `git-state-injector`, `ticket-linker`, `spec-reminder`
8+
59
### Dashboard
610
- **First-party dashboard** — replaced third-party `claude-session-dashboard` npm package with `codeforge-dashboard` (built from monorepo `dashboard/` package)
711
- Auto-launch on container start via poststart hook (controllable with `autostart` option)

container/.devcontainer/CLAUDE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CodeForge devcontainer for AI-assisted development with Claude Code.
1010
| `.codeforge/config/main-system-prompt.md` | System prompt defining assistant behavior |
1111
| `.codeforge/config/orchestrator-system-prompt.md` | Orchestrator mode prompt (delegation-first) |
1212
| `.codeforge/config/ccstatusline-settings.json` | Status bar widget layout (deployed to ~/.config/ccstatusline/) |
13+
| `.codeforge/config/disabled-hooks.json` | Disable individual plugin hooks by script name |
1314
| `.codeforge/file-manifest.json` | Controls which config files deploy and when |
1415
| `devcontainer.json` | Container definition: image, features, mounts |
1516
| `.env` | Boolean flags controlling setup steps |
@@ -78,6 +79,7 @@ The `~/.claude/` directory is backed by a Docker named volume (`codeforge-claude
7879
5. **Disable features**: Set `"version": "none"` in the feature's config
7980
6. **Disable setup steps**: Set flags to `false` in `.env`
8081
7. **Customize status bar**: Edit `.codeforge/config/ccstatusline-settings.json`
82+
8. **Disable individual hooks**: Add script name (without `.py`) to `disabled` array in `.codeforge/config/disabled-hooks.json` — takes effect immediately, no restart needed
8183

8284
## Plugin Development Notes
8385

container/.devcontainer/devcontainer.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@
123123
},
124124
// Uncomment to add ccms (requires Rust):
125125
// "./features/ccms": {},
126-
"./features/claude-session-dashboard": {
127-
"version": "latest",
128-
"port": "7847",
129-
"shells": "both",
130-
"username": "automatic"
131-
},
126+
// "./features/claude-session-dashboard": {
127+
// "version": "latest",
128+
// "port": "7847",
129+
// "shells": "both",
130+
// "username": "automatic"
131+
// },
132132
"./features/ast-grep": {},
133133
"./features/tree-sitter": {},
134134
"./features/lsp-servers": {},

container/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/guard-readonly-bash.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
import json
2121
import re
2222
import sys
23+
import os
24+
25+
# Hook gate — check .codeforge/config/disabled-hooks.json
26+
_dh = os.path.join(os.getcwd(), ".codeforge", "config", "disabled-hooks.json")
27+
if os.path.exists(_dh):
28+
with open(_dh) as _f:
29+
if os.path.basename(__file__).replace(".py", "") in json.load(_f).get("disabled", []):
30+
sys.exit(0)
2331

2432
# ---------------------------------------------------------------------------
2533
# General-readonly blocklist

container/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/redirect-builtin-agents.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
import json
2121
import sys
2222
from datetime import datetime, timezone
23+
import os
24+
25+
# Hook gate — check .codeforge/config/disabled-hooks.json
26+
_dh = os.path.join(os.getcwd(), ".codeforge", "config", "disabled-hooks.json")
27+
if os.path.exists(_dh):
28+
with open(_dh) as _f:
29+
if os.path.basename(__file__).replace(".py", "") in json.load(_f).get("disabled", []):
30+
sys.exit(0)
2331

2432
# Built-in agent type → custom agent name mapping
2533
REDIRECT_MAP = {

container/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/task-completed-check.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
import subprocess
1515
import sys
1616

17+
# Hook gate — check .codeforge/config/disabled-hooks.json
18+
_dh = os.path.join(os.getcwd(), ".codeforge", "config", "disabled-hooks.json")
19+
if os.path.exists(_dh):
20+
with open(_dh) as _f:
21+
if os.path.basename(__file__).replace(".py", "") in json.load(_f).get("disabled", []):
22+
sys.exit(0)
23+
1724
TIMEOUT_SECONDS = 60
1825

1926

container/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/teammate-idle-check.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@
1313
import os
1414
import sys
1515

16+
# Hook gate — check .codeforge/config/disabled-hooks.json
17+
_dh = os.path.join(os.getcwd(), ".codeforge", "config", "disabled-hooks.json")
18+
if os.path.exists(_dh):
19+
with open(_dh) as _f:
20+
if os.path.basename(__file__).replace(".py", "") in json.load(_f).get("disabled", []):
21+
sys.exit(0)
22+
1623

1724
def find_incomplete_tasks(teammate_name: str) -> list[str]:
1825
"""Scan task directories for incomplete tasks owned by this teammate."""

container/.devcontainer/plugins/devs-marketplace/plugins/agent-system/scripts/verify-no-regression.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
import sys
2020
import time
2121

22+
# Hook gate — check .codeforge/config/disabled-hooks.json
23+
_dh = os.path.join(os.getcwd(), ".codeforge", "config", "disabled-hooks.json")
24+
if os.path.exists(_dh):
25+
with open(_dh) as _f:
26+
if os.path.basename(__file__).replace(".py", "") in json.load(_f).get("disabled", []):
27+
sys.exit(0)
28+
2229
DEBOUNCE_SECONDS = 10
2330

2431

0 commit comments

Comments
 (0)