Skip to content

feat: add kaizen plugin for Claude Code guidelines - #41

Merged
visahak merged 4 commits into
AgentToolkit:mainfrom
vinodmut:kaizen-plugin
Jan 29, 2026
Merged

feat: add kaizen plugin for Claude Code guidelines#41
visahak merged 4 commits into
AgentToolkit:mainfrom
vinodmut:kaizen-plugin

Conversation

@vinodmut

@vinodmut vinodmut commented Jan 28, 2026

Copy link
Copy Markdown
Contributor

For #36

I'll update the plugin install docs once this is merged. I can only test that once it's in the git repo.

Summary by CodeRabbit

  • New Features

    • Added Kaizen plugin: auto-learns guidelines from conversations, retrieves relevant guidance during prompts, and persistently saves updates via automated hooks and helper scripts.
    • Marketplace manifest added for easy discovery and install.
  • Documentation

    • Added plugin README, INSTALL guide, and skill docs for guideline generation and retrieval.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Jan 28, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Introduce the Kaizen plugin: marketplace and plugin manifests, documentation, hook configuration, and two scripts to retrieve and save conversation-derived guidelines.

Changes

Cohort / File(s) Summary
Marketplace & Plugin Manifests
​.claude-plugin/marketplace.json, plugins/kaizen/​.claude-plugin/plugin.json
Add marketplace manifest and plugin manifest registering the Kaizen plugin with metadata, version, author, category, and skills path.
Documentation
plugins/kaizen/README.md, plugins/kaizen/INSTALL.md, plugins/kaizen/skills/guideline-generator/SKILL.md, plugins/kaizen/skills/guideline-retrieval/SKILL.md
Add README, install guide, and skill docs describing plugin operation, schemas, workflows, environment variables, and verification steps.
Hook Configuration
plugins/kaizen/hooks/hooks.json
Add hook pipeline invoking retrieval on UserPromptSubmit and saving on Stop, referencing command hooks that run plugin scripts.
Guidelines Scripts
plugins/kaizen/scripts/retrieve_guidelines.py, plugins/kaizen/scripts/save_guidelines.py
Add retrieval script to discover/load/format guidelines and save script to parse, merge (deduplicate), and persist guidelines; both include logging and stdin/stdout interfaces.

Sequence Diagram(s)

sequenceDiagram
    participant User as User/Client
    participant Hook as Hook System
    participant Retrieve as retrieve_guidelines.py
    participant File as Guidelines File
    participant Claude as Claude Processor

    User->>Hook: Submit prompt (UserPromptSubmit)
    Hook->>Retrieve: Execute retrieval script
    Retrieve->>Retrieve: Discover guidelines file path
    Retrieve->>File: Read guidelines.json
    File-->>Retrieve: Return guidelines data
    Retrieve->>Retrieve: Format guidelines (Markdown)
    Retrieve-->>Claude: Write formatted guidelines to stdout
    Claude->>Claude: Apply guidelines during response generation
Loading
sequenceDiagram
    participant Claude as Claude (Generator)
    participant Save as save_guidelines.py
    participant File as Guidelines File
    participant Operator as Operator/User

    Claude->>Save: Emit new guidelines JSON via stdin
    Save->>Save: Determine target file path (existing or default)
    Save->>File: Load existing guidelines (if any)
    File-->>Save: Return existing guidelines
    Save->>Save: Merge and deduplicate by "content"
    Save->>File: Write merged guidelines JSON
    Save-->>Operator: Output status (created/appended, counts, path)
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Poem

A rabbit nibbles notes so fine,
Hooks and scripts in tidy line,
Kaizen listens, learns, and saves,
Turning chats into wiser ways,
Hopping forward, one guideline at a time. 🐇✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: adding a kaizen plugin for Claude Code guidelines. It is concise, specific, and clearly communicates the primary purpose of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In `@plugins/kaizen/INSTALL.md`:
- Around line 73-75: Update the INSTALL.md troubleshooting examples to reference
the actual log path used by the scripts: replace occurrences of
"/tmp/guidelines.txt" with "/tmp/guidelines-plugin.log" (affecting the examples
around the lines mentioning the debug log and the expected output), so the docs
match the scripts that write to /tmp/guidelines-plugin.log.
- Around line 10-46: Update INSTALL.md to use the correct plugin name "kaizen"
everywhere: replace instances of "guidelines-plugin" and "guidelines" in the
example commands and alias with "kaizen" (e.g., change `claude --plugin-dir
./guidelines-plugin`, `alias claude='claude --plugin-dir
/path/to/guidelines-plugin'`, and `claude plugin install guidelines` to use
"kaizen"), ensuring the marketplace install command `claude plugin install
kaizen` and the plugin-dir examples reference the kaizen plugin name
consistently.

In `@plugins/kaizen/README.md`:
- Around line 80-95: Update the README code block so the plugin root name
matches the actual plugin ("kaizen/") instead of "guidelines-plugin/" and add a
language specifier to the fenced block (e.g., ```text) so the tree is rendered
correctly; edit the fenced code block in README.md that contains the directory
tree and replace the first line "guidelines-plugin/" with "kaizen/" and change
the opening backticks to "```text".
- Around line 13-19: The README installation examples use the wrong plugin
directory name; update the examples in README.md to reference the actual plugin
name defined in plugin.json ("kaizen") instead of "guidelines-plugin" — change
occurrences like "claude --plugin-dir ./guidelines-plugin" to "claude
--plugin-dir ./plugins/kaizen" and "claude --plugin-dir
/path/to/guidelines-plugin" to "claude --plugin-dir /path/to/kaizen" so the
example matches the plugin.json name.
- Around line 32-37: The README's "Guideline Generation (Stop hook)" section is
misleading because hooks.json only defines a UserPromptSubmit hook and there is
no Stop/ConversationEnd hook implemented; update the README to either remove or
reword that section to state that guideline extraction is performed manually via
the /guidelines:generator command (or, alternatively, implement a proper
Stop/ConversationEnd hook that triggers guideline extraction and add its details
to hooks.json and README). Ensure references to the existing UserPromptSubmit
hook remain accurate and explicitly note that automatic end-of-conversation
extraction is not currently implemented unless you add the new hook.

In `@plugins/kaizen/scripts/retrieve_guidelines.py`:
- Around line 60-66: The loop over guidelines can raise a KeyError when an entry
lacks 'content'; update the loop that builds items (the for g in guidelines:
block) to skip invalid entries by checking for g.get('content') (or 'content' in
g) and continue if missing, and then use a local content variable (e.g., content
= g.get('content')) when constructing item; this prevents crashes and ensures
only valid guideline objects are formatted and appended to items.
- Around line 10-17: Replace the hard-coded LOG_FILE and update the log()
function so the log path is configurable and created safely: make LOG_FILE a
configurable variable (e.g., default to a project ".claude" dir or the user
state dir) and resolve it at module init, ensure the parent directory exists
(create it if missing) with proper permissions before any writes, and continue
to use the existing log(message) function to append timestamped entries; refer
to LOG_FILE and log() in retrieve_guidelines.py when making these changes.

In `@plugins/kaizen/scripts/save_guidelines.py`:
- Around line 110-118: The merge loop currently appends any guideline lacking a
valid content field; update the loop that iterates new_guidelines (used with
existing_guidelines, existing_contents, added_count) to first validate
guideline.get("content") is a non-empty string (e.g., check for None, empty or
whitespace-only values and optionally strip()) and skip entries that fail
validation before deduplication; ensure existing_contents uses the
normalized/stripped content for comparison so only valid, non-duplicate
guidelines are appended and counted.
- Around line 13-20: The hard-coded LOG_FILE (LOG_FILE) and the log() function
use a predictable /tmp path; change LOG_FILE to be configurable (read from an
environment variable or shared constant used by the retrieve script) and avoid a
fixed "/tmp" value, and before opening the file ensure the parent directory
exists by creating it with os.makedirs(..., exist_ok=True) and proper
permissions; update save_guidelines.py so log() uses that configurable LOG_FILE
and creates the directory if missing to match the retrieve script's behavior.

Comment thread plugins/kaizen/INSTALL.md
Comment on lines +10 to +46
Use `--plugin-dir` to load the plugin for a session:

```bash
# Load plugin when starting Claude Code (absolute path)
claude --plugin-dir /path/to/guidelines-plugin

# Or use a relative path from current directory
claude --plugin-dir ./guidelines-plugin
```

**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/guidelines-plugin'
```

Then reload your shell:

```bash
source ~/.zshrc # or source ~/.bashrc
```

## Option 2: Install from Marketplace (when published)

```bash
claude plugin install guidelines
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find manifest files in plugins/kaizen directory
find plugins/kaizen -type f -name "manifest.*" -o -name "package.json" | head -20

Repository: AgentToolkit/kaizen

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Read the INSTALL.md file to see actual content
cat -n plugins/kaizen/INSTALL.md

Repository: AgentToolkit/kaizen

Length of output: 3304


🏁 Script executed:

#!/bin/bash
# Search for manifest files in the plugins/kaizen directory
find plugins/kaizen -type f \( -name "*.json" \) | grep -E "(manifest|package)" | head -20

Repository: AgentToolkit/kaizen

Length of output: 45


🏁 Script executed:

#!/bin/bash
# List all files in plugins/kaizen to understand structure
ls -la plugins/kaizen/

Repository: AgentToolkit/kaizen

Length of output: 524


🏁 Script executed:

#!/bin/bash
# Check the .claude-plugin directory
ls -la plugins/kaizen/.claude-plugin/

Repository: AgentToolkit/kaizen

Length of output: 231


🏁 Script executed:

#!/bin/bash
# Read manifest files in .claude-plugin
find plugins/kaizen/.claude-plugin -type f -exec cat {} \;

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 uses guidelines and guidelines-plugin throughout. 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)
-claude --plugin-dir /path/to/guidelines-plugin
+claude --plugin-dir /path/to/kaizen

-claude --plugin-dir ./guidelines-plugin
+claude --plugin-dir ./kaizen

-alias claude='claude --plugin-dir /path/to/guidelines-plugin'
+alias claude='claude --plugin-dir /path/to/kaizen'

-claude plugin validate /path/to/guidelines-plugin
+claude plugin validate /path/to/kaizen

-claude --plugin-dir ./guidelines-plugin
+claude --plugin-dir ./kaizen

-run `claude plugin validate ./guidelines-plugin`
+run `claude plugin validate ./kaizen`

-check script permissions: `ls -la guidelines-plugin/scripts/`
+check script permissions: `ls -la kaizen/scripts/`

-claude plugin install guidelines
+claude plugin install kaizen
🤖 Prompt for AI Agents
In `@plugins/kaizen/INSTALL.md` around lines 10 - 46, Update INSTALL.md to use the
correct plugin name "kaizen" everywhere: replace instances of
"guidelines-plugin" and "guidelines" in the example commands and alias with
"kaizen" (e.g., change `claude --plugin-dir ./guidelines-plugin`, `alias
claude='claude --plugin-dir /path/to/guidelines-plugin'`, and `claude plugin
install guidelines` to use "kaizen"), ensuring the marketplace install command
`claude plugin install kaizen` and the plugin-dir examples reference the kaizen
plugin name consistently.

Comment thread plugins/kaizen/INSTALL.md Outdated
Comment thread plugins/kaizen/README.md
Comment thread plugins/kaizen/README.md
Comment thread plugins/kaizen/README.md Outdated
Comment on lines +10 to +17
# 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")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid fixed log file under /tmp (predictable path).

Use a safer, configurable location (project .claude or user state dir) and ensure the parent directory exists before writing.

🔒 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
In `@plugins/kaizen/scripts/retrieve_guidelines.py` around lines 10 - 17, Replace
the hard-coded LOG_FILE and update the log() function so the log path is
configurable and created safely: make LOG_FILE a configurable variable (e.g.,
default to a project ".claude" dir or the user state dir) and resolve it at
module init, ensure the parent directory exists (create it if missing) with
proper permissions before any writes, and continue to use the existing
log(message) function to append timestamped entries; refer to LOG_FILE and log()
in retrieve_guidelines.py when making these changes.

Comment thread plugins/kaizen/scripts/retrieve_guidelines.py
Comment on lines +13 to +20
# 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}] [save] {message}\n")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use a safer, configurable log file location.

Fixed /tmp log paths are predictable; keep this aligned with the retrieve script and ensure the directory exists.

🔒 Proposed fix (align with retrieve script)
-# 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}] [save] {message}\n")
🧰 Tools
🪛 Ruff (0.14.14)

14-14: Probable insecure usage of temporary file or directory: "/tmp/guidelines-plugin.log"

(S108)

🤖 Prompt for AI Agents
In `@plugins/kaizen/scripts/save_guidelines.py` around lines 13 - 20, The
hard-coded LOG_FILE (LOG_FILE) and the log() function use a predictable /tmp
path; change LOG_FILE to be configurable (read from an environment variable or
shared constant used by the retrieve script) and avoid a fixed "/tmp" value, and
before opening the file ensure the parent directory exists by creating it with
os.makedirs(..., exist_ok=True) and proper permissions; update
save_guidelines.py so log() uses that configurable LOG_FILE and creates the
directory if missing to match the retrieve script's behavior.

Comment thread plugins/kaizen/scripts/save_guidelines.py
Wire save_guidelines.py to run when conversations end, enabling
automatic extraction and storage of guidelines from session context.
- Rename plugin references from guidelines-plugin to kaizen in docs
- Update log file path references to guidelines-plugin.log
- Add null checks for guideline content in retrieve and save scripts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@plugins/kaizen/scripts/retrieve_guidelines.py`:
- Around line 22-32: The find_guidelines_file function currently searches
.claude/guidelines.json and plugin-relative paths but misses the plain
guidelines.json that save_guidelines.py writes to the current working directory
when CLAUDE_PROJECT_ROOT is unset; update the locations list in
find_guidelines_file to include the cwd-root file (e.g., Path.cwd()/
"guidelines.json" or os.path.join(os.getcwd(), "guidelines.json")) so
retrieve_guidelines.py aligns with save_guidelines.py and will find guidelines
saved to the working directory.

Comment on lines +22 to +32
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"),
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align guideline search paths with save_guidelines.py to avoid “write-but-never-read”.

If CLAUDE_PROJECT_ROOT is unset and .claude/ doesn’t exist, save_guidelines.py writes guidelines.json in the cwd. retrieve_guidelines.py never searches that location, so saved guidelines won’t be retrieved.

🛠️ 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
In `@plugins/kaizen/scripts/retrieve_guidelines.py` around lines 22 - 32, The
find_guidelines_file function currently searches .claude/guidelines.json and
plugin-relative paths but misses the plain guidelines.json that
save_guidelines.py writes to the current working directory when
CLAUDE_PROJECT_ROOT is unset; update the locations list in find_guidelines_file
to include the cwd-root file (e.g., Path.cwd()/ "guidelines.json" or
os.path.join(os.getcwd(), "guidelines.json")) so retrieve_guidelines.py aligns
with save_guidelines.py and will find guidelines saved to the working directory.

Ensure save_guidelines.py and retrieve_guidelines.py use identical
search paths. Always create .claude/guidelines.json instead of falling
back to guidelines.json in cwd which retrieve would never find.
@vinodmut

Copy link
Copy Markdown
Contributor Author

I think I fixed the coderabbit feedback with the subsequent commits to this PR.

@visahak visahak left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@visahak
visahak merged commit e20bcd3 into AgentToolkit:main Jan 29, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants