-
Notifications
You must be signed in to change notification settings - Fork 11
feat: add kaizen plugin for Claude Code guidelines #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d3f24af
cea3088
df844ee
e46df49
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", | ||
| "name": "kaizen-marketplace", | ||
| "description": "Kaizen plugins for Claude Code - continuous improvement through auto-generated guidelines", | ||
| "owner": { | ||
| "name": "Vinod Muthusamy" | ||
| }, | ||
| "plugins": [ | ||
| { | ||
| "name": "kaizen", | ||
| "description": "Learn from conversations with auto-generated guidelines", | ||
| "version": "1.0.0", | ||
| "author": { | ||
| "name": "Vinod Muthusamy" | ||
| }, | ||
| "source": "./plugins/kaizen", | ||
| "category": "productivity" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| { | ||
| "name": "kaizen", | ||
| "version": "1.0.0", | ||
| "description": "Learn from conversations with auto-generated guidelines", | ||
| "author": { | ||
| "name": "Vinod Muthusamy" | ||
| }, | ||
| "skills": "./skills/" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| # Installation Guide | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed | ||
| - Python 3.8+ available in PATH | ||
|
|
||
| ## Option 1: Load Local Plugin (Development) | ||
|
|
||
| Use `--plugin-dir` to load the plugin for a session: | ||
|
|
||
| ```bash | ||
| # Load plugin when starting Claude Code (absolute path) | ||
| claude --plugin-dir /path/to/kaizen | ||
|
|
||
| # Or use a relative path from current directory | ||
| claude --plugin-dir ./kaizen | ||
| ``` | ||
|
|
||
| **Note:** The plugin is loaded **for that session only**. | ||
|
|
||
| ### Loading Multiple Plugins | ||
|
|
||
| ```bash | ||
| claude --plugin-dir ./plugin1 --plugin-dir ./plugin2 | ||
| ``` | ||
|
|
||
| ### Making It Permanent | ||
|
|
||
| Add an alias to your shell profile (`~/.bashrc` or `~/.zshrc`): | ||
|
|
||
| ```bash | ||
| alias claude='claude --plugin-dir /path/to/kaizen' | ||
| ``` | ||
|
|
||
| Then reload your shell: | ||
|
|
||
| ```bash | ||
| source ~/.zshrc # or source ~/.bashrc | ||
| ``` | ||
|
|
||
| ## Option 2: Install from Marketplace (when published) | ||
|
|
||
| ```bash | ||
| claude plugin install kaizen | ||
| ``` | ||
|
|
||
| ## Validate Plugin | ||
|
|
||
| Before using, validate the plugin manifest: | ||
|
|
||
| ```bash | ||
| claude plugin validate /path/to/kaizen | ||
| # Should output: ✔ Validation passed | ||
| ``` | ||
|
|
||
| ## Initialize Guidelines File (Optional) | ||
|
|
||
| ```bash | ||
| mkdir -p .claude | ||
| echo '{"guidelines": []}' > .claude/guidelines.json | ||
| ``` | ||
|
|
||
| ## Verification | ||
|
|
||
| After loading the plugin, verify it's working: | ||
|
|
||
| 1. **Test hook execution:** | ||
| ```bash | ||
| # Start Claude Code with the plugin | ||
| claude --plugin-dir ./kaizen | ||
|
|
||
| # Send any prompt, then check the debug log (in another terminal) | ||
| cat /tmp/guidelines-plugin.log | ||
| # Should show: "[retrieve] Script started" with timestamp | ||
| ``` | ||
|
|
||
| 2. **Test guideline storage:** | ||
| ```bash | ||
| # After ending a conversation where guidelines were generated | ||
| cat .claude/guidelines.json | ||
| # Should contain the extracted guidelines | ||
| ``` | ||
|
|
||
| 3. **Test skills manually:** | ||
| ```bash | ||
| # In a Claude Code session with the plugin loaded, invoke: | ||
| /guidelines:generator | ||
| /guidelines:retrieval | ||
| ``` | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Plugin validation fails | ||
|
|
||
| Run `claude plugin validate ./kaizen` to see specific errors. | ||
|
|
||
| ### Hooks not firing | ||
|
|
||
| 1. Verify the plugin is loaded with `--plugin-dir` | ||
| 2. Verify Python is in PATH: `which python3` | ||
| 3. Check script permissions: `ls -la kaizen/scripts/` | ||
| 4. Check debug log: `cat /tmp/guidelines-plugin.log` | ||
|
|
||
| ### Guidelines not saving | ||
|
|
||
| 1. Verify `.claude/` directory exists in your project | ||
| 2. Check write permissions on the directory | ||
| 3. Review `/tmp/guidelines-plugin.log` for error messages | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Guidelines Plugin for Claude Code | ||
|
|
||
| A plugin that helps Claude Code learn from conversations by automatically extracting and applying guidelines. | ||
|
|
||
| ## Features | ||
|
|
||
| - **Automatic Learning**: At the end of each conversation, guidelines are extracted and saved | ||
| - **Context-Aware Retrieval**: At the start of each prompt, relevant guidelines are injected | ||
| - **No Manual Configuration**: Hooks are automatically installed when the plugin is enabled | ||
|
|
||
| ## Installation | ||
|
|
||
| ```bash | ||
| # Load plugin for current session | ||
| claude --plugin-dir ./kaizen | ||
|
|
||
| # Or with absolute path | ||
| claude --plugin-dir /path/to/kaizen | ||
| ``` | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| See [INSTALL.md](INSTALL.md) for making it permanent, loading multiple plugins, and troubleshooting. | ||
|
|
||
| ## How It Works | ||
|
|
||
| ### Guideline Retrieval (UserPromptSubmit hook) | ||
|
|
||
| When you submit a prompt, the plugin: | ||
| 1. Loads all stored guidelines from `.claude/guidelines.json` | ||
| 2. Formats and injects them into the conversation context | ||
| 3. Claude applies relevant guidelines to the current task | ||
|
|
||
| ### Guideline Generation (Stop hook) | ||
|
|
||
| When a conversation ends, the plugin: | ||
| 1. Analyzes the conversation trajectory | ||
| 2. Extracts actionable guidelines from what worked/failed | ||
| 3. Saves new guidelines to `.claude/guidelines.json` | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| ## Skills Included | ||
|
|
||
| ### `/guidelines:generator` | ||
|
|
||
| Manually invoke to extract guidelines from the current conversation: | ||
| - Analyzes task, steps taken, successes and failures | ||
| - Generates proactive guidelines (what to do, not what to avoid) | ||
| - Outputs JSON for storage | ||
|
|
||
| ### `/guidelines:retrieval` | ||
|
|
||
| Manually invoke to retrieve and display stored guidelines. | ||
|
|
||
| ## Guidelines Storage | ||
|
|
||
| Guidelines are stored in `.claude/guidelines.json`: | ||
|
|
||
| ```json | ||
| { | ||
| "guidelines": [ | ||
| { | ||
| "content": "Use Python PIL/Pillow for image metadata extraction in sandboxed environments", | ||
| "rationale": "System tools like exiftool may not be available", | ||
| "category": "strategy", | ||
| "trigger": "When extracting image metadata in containerized environments" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| - `GUIDELINES_FILE`: Override the default guidelines storage location | ||
| - `CLAUDE_PROJECT_ROOT`: Set by Claude Code, used to locate project-level guidelines | ||
|
|
||
| ## Verification | ||
|
|
||
| After installation, run `claude plugin list` to confirm the plugin is enabled. See [INSTALL.md](INSTALL.md) for detailed verification steps. | ||
|
|
||
| ## Plugin Structure | ||
|
|
||
| ```text | ||
| kaizen/ | ||
| ├── .claude-plugin/ | ||
| │ └── plugin.json # Plugin manifest | ||
| ├── skills/ | ||
| │ ├── guideline-generator/ | ||
| │ │ └── SKILL.md | ||
| │ └── guideline-retrieval/ | ||
| │ └── SKILL.md | ||
| ├── hooks/ | ||
| │ └── hooks.json # Auto-configured hooks | ||
| ├── scripts/ | ||
| │ ├── save_guidelines.py | ||
| │ └── retrieve_guidelines.py | ||
| └── README.md | ||
| ``` | ||
|
|
||
| ## License | ||
|
|
||
| MIT | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "hooks": { | ||
| "UserPromptSubmit": [ | ||
| { | ||
| "matcher": "", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/retrieve_guidelines.py" | ||
| } | ||
| ] | ||
| } | ||
| ], | ||
| "Stop": [ | ||
| { | ||
| "matcher": "", | ||
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "python3 ${CLAUDE_PLUGIN_ROOT}/scripts/save_guidelines.py" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| #!/usr/bin/env python3 | ||
| """Retrieve and output guidelines for Claude to filter.""" | ||
|
|
||
| import json | ||
| import os | ||
| import sys | ||
| from pathlib import Path | ||
| import datetime | ||
|
|
||
| # Debug logging | ||
| LOG_FILE = "/tmp/guidelines-plugin.log" | ||
|
|
||
| def log(message): | ||
| """Append a timestamped message to the log file.""" | ||
| timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") | ||
| with open(LOG_FILE, "a") as f: | ||
| f.write(f"[{timestamp}] [retrieve] {message}\n") | ||
|
Comment on lines
+10
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid fixed log file under Use a safer, configurable location (project 🔒 Proposed fix (configurable, safer log path)-# Debug logging
-LOG_FILE = "/tmp/guidelines-plugin.log"
+# Debug logging
+LOG_FILE = os.environ.get(
+ "GUIDELINES_LOG_FILE",
+ str(
+ (
+ Path(os.environ.get("CLAUDE_PROJECT_ROOT", ""))
+ if os.environ.get("CLAUDE_PROJECT_ROOT")
+ else Path.home() / ".local" / "state" / "kaizen"
+ )
+ / ".claude"
+ / "guidelines-plugin.log"
+ ),
+)
def log(message):
"""Append a timestamped message to the log file."""
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- with open(LOG_FILE, "a") as f:
+ Path(LOG_FILE).parent.mkdir(parents=True, exist_ok=True)
+ with open(LOG_FILE, "a") as f:
f.write(f"[{timestamp}] [retrieve] {message}\n")🧰 Tools🪛 Ruff (0.14.14)11-11: Probable insecure usage of temporary file or directory: "/tmp/guidelines-plugin.log" (S108) 🤖 Prompt for AI Agents |
||
|
|
||
| log("Script started") | ||
|
|
||
|
|
||
| def find_guidelines_file(): | ||
| """Find the guidelines file in common locations.""" | ||
| locations = [ | ||
| os.environ.get("GUIDELINES_FILE"), | ||
| # Project root from Claude Code | ||
| os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".claude/guidelines.json"), | ||
| # Current working directory | ||
| ".claude/guidelines.json", | ||
| # Plugin-relative path (fallback) | ||
| str(Path(__file__).parent.parent / "guidelines.json"), | ||
| ] | ||
|
Comment on lines
+22
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Align guideline search paths with save_guidelines.py to avoid “write-but-never-read”. If 🛠️ Suggested fix (include cwd guidelines.json) def find_guidelines_file():
"""Find the guidelines file in common locations."""
locations = [
os.environ.get("GUIDELINES_FILE"),
# Project root from Claude Code
os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".claude/guidelines.json"),
# Current working directory
".claude/guidelines.json",
+ # CWD fallback (aligned with save_guidelines.py default)
+ "guidelines.json",
# Plugin-relative path (fallback)
str(Path(__file__).parent.parent / "guidelines.json"),
]🤖 Prompt for AI Agents |
||
| for loc in locations: | ||
| if loc and Path(loc).exists(): | ||
| return Path(loc) | ||
| return None | ||
|
|
||
|
|
||
| def load_guidelines(): | ||
| """Load guidelines from the guidelines file.""" | ||
| guidelines_file = find_guidelines_file() | ||
| if not guidelines_file: | ||
| return [] | ||
| try: | ||
| with open(guidelines_file) as f: | ||
| data = json.load(f) | ||
| return data.get("guidelines", []) | ||
| except (json.JSONDecodeError, IOError): | ||
| return [] | ||
|
|
||
|
|
||
| def format_guidelines(guidelines): | ||
| """Format all guidelines for Claude to review.""" | ||
| header = """## Guidelines for this task | ||
|
|
||
| Review these guidelines and apply any relevant ones: | ||
|
|
||
| """ | ||
| items = [] | ||
| for g in guidelines: | ||
| content = g.get('content') | ||
| if not content: | ||
| continue | ||
| item = f"- **[{g.get('category', 'general')}]** {content}" | ||
| if g.get('rationale'): | ||
| item += f"\n - _Rationale: {g['rationale']}_" | ||
| if g.get('trigger'): | ||
| item += f"\n - _When: {g['trigger']}_" | ||
| items.append(item) | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| return header + "\n".join(items) | ||
|
|
||
|
|
||
| def main(): | ||
| # Read input from stdin (hook provides JSON with prompt) | ||
| try: | ||
| input_data = json.load(sys.stdin) | ||
| log(f"Received input with keys: {list(input_data.keys())}") | ||
| except json.JSONDecodeError as e: | ||
| log(f"Failed to parse JSON input: {e}") | ||
| return | ||
|
|
||
| # Load all guidelines | ||
| guidelines_file = find_guidelines_file() | ||
| log(f"Guidelines file: {guidelines_file}") | ||
|
|
||
| guidelines = load_guidelines() | ||
| if not guidelines: | ||
| log("No guidelines found") | ||
| return | ||
|
|
||
| log(f"Loaded {len(guidelines)} guidelines") | ||
|
|
||
| # Output all guidelines - Claude will filter for relevance | ||
| output = format_guidelines(guidelines) | ||
| print(output) | ||
| log(f"Output {len(output)} chars to stdout") | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: AgentToolkit/kaizen
Length of output: 45
🏁 Script executed:
Repository: AgentToolkit/kaizen
Length of output: 3304
🏁 Script executed:
Repository: AgentToolkit/kaizen
Length of output: 45
🏁 Script executed:
Repository: AgentToolkit/kaizen
Length of output: 524
🏁 Script executed:
Repository: AgentToolkit/kaizen
Length of output: 231
🏁 Script executed:
Repository: AgentToolkit/kaizen
Length of output: 257
Fix plugin name mismatch in install instructions.
The marketplace manifest registers this plugin as
kaizen, but INSTALL.md usesguidelinesandguidelines-pluginthroughout. The marketplace install command on line 45 will fail, and users following the directory path examples will get incorrect commands.Update all references to use
kaizen:🛠️ Proposed fix (align naming)
🤖 Prompt for AI Agents