import from local vendored copy (2026-05-06)
Some checks failed
CI / validate (push) Failing after 0s

This commit is contained in:
Hongming Wang 2026-05-06 13:53:27 -07:00
commit 004e9ed5d7
10 changed files with 150 additions and 0 deletions

5
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,5 @@
name: CI
on: [push, pull_request]
jobs:
validate:
uses: Molecule-AI/molecule-ci/.github/workflows/validate-plugin.yml@main

21
.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# Credentials — never commit. Use .env.example as the template.
.env
.env.local
.env.*.local
.env.*
!.env.example
!.env.sample
# Private keys + certs
*.pem
*.key
*.crt
*.p12
*.pfx
# Secret directories
.secrets/
# Workspace auth tokens
.auth-token
.auth_token

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# molecule-freeze-scope
Molecule AI plugin. Install via the Molecule AI platform plugin system.
## Usage
### In org template (org.yaml)
```yaml
plugins:
- molecule-freeze-scope
```
### From URL (community install)
```
github://Molecule-AI/molecule-ai-plugin-molecule-freeze-scope
```
## License
Business Source License 1.1 — © Molecule AI.

0
adapters/__init__.py Normal file
View File

2
adapters/claude_code.py Normal file
View File

@ -0,0 +1,2 @@
"""Claude Code adaptor — uses the generic rule+skill+hooks installer."""
from plugins_registry.builtins import AgentskillsAdaptor as Adaptor # noqa: F401

46
hooks/_lib.py Executable file
View File

@ -0,0 +1,46 @@
"""Common helpers for Claude Code hooks. Imported by the .py hook scripts.
Hooks receive JSON on stdin per the Claude Code hook spec, and may emit
JSON on stdout or exit with code 2 to block. This module wraps both.
"""
import json
import sys
def read_input() -> dict:
"""Parse stdin JSON. Empty input → empty dict."""
raw = sys.stdin.read().strip()
if not raw:
return {}
try:
return json.loads(raw)
except json.JSONDecodeError:
return {}
def emit(payload: dict) -> None:
"""Print JSON payload to stdout for the harness to interpret."""
print(json.dumps(payload))
def deny_pretooluse(reason: str) -> None:
"""Emit a PreToolUse denial with reason and exit 0."""
emit({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": reason,
}
})
sys.exit(0)
def add_context(text: str) -> None:
"""Emit additionalContext for SessionStart / UserPromptSubmit hooks."""
if text and text.strip():
emit({"additionalContext": text})
def warn_to_stderr(msg: str) -> None:
"""Non-blocking warning visible to the next agent turn via stderr."""
print(msg, file=sys.stderr)

43
hooks/pre-edit-freeze.py Executable file
View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""PreToolUse:Edit/Write — enforce /freeze scope from .claude/freeze."""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from _lib import read_input, deny_pretooluse, warn_to_stderr # noqa
REPO = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
FREEZE = os.path.join(REPO, ".claude", "freeze")
def main() -> None:
if not os.path.isfile(FREEZE):
return
with open(FREEZE) as f:
allowed = f.readline().strip()
if not allowed:
return
data = read_input()
target = data.get("tool_input", {}).get("file_path") or data.get("tool_input", {}).get("notebook_path") or ""
if not target:
return
# Always allow .claude/ writes (so unfreeze still works)
if "/.claude/" in target or target.endswith("/.claude") or "/.claude" in target:
return
if allowed in target:
return
deny_pretooluse(
f"freeze: edit to {target} refused — scope locked to '{allowed}'. "
f"Remove .claude/freeze to unlock."
)
if __name__ == "__main__":
try:
main()
except Exception as e:
warn_to_stderr(f"[freeze hook error] {e}")
sys.exit(0)

2
hooks/pre-edit-freeze.sh Executable file
View File

@ -0,0 +1,2 @@
#!/usr/bin/env bash
exec python3 "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/pre-edit-freeze.py"

11
plugin.yaml Normal file
View File

@ -0,0 +1,11 @@
name: molecule-freeze-scope
version: 1.0.0
description: Lock edits to a single path glob via .claude/freeze. PreToolUse:Edit/Write hook.
author: Molecule AI
tags: [molecule, guardrails]
runtimes:
- claude_code
hooks:
- pre-edit-freeze

1
settings-fragment.json Normal file
View File

@ -0,0 +1 @@
{"hooks":{"PreToolUse":[{"matcher":"Edit|Write|NotebookEdit","hooks":[{"type":"command","command":"bash ${CLAUDE_DIR}/hooks/pre-edit-freeze.sh"}]}]}}