From 0ea7fb7b410dfbe369f13bbc6f11b1d4d4266182 Mon Sep 17 00:00:00 2001 From: Vinod Muthusamy Date: Mon, 23 Feb 2026 11:52:18 -0600 Subject: [PATCH 1/2] feat: move entity storage to .kaizen/ and add Kaizen Lite guide Move entity storage from .claude/entities.json to .kaizen/entities.json so the plugin has its own dedicated workspace directory. Add KAIZEN_LITE.md documenting the lightweight plugin-only mode that requires no vector DB, MCP servers, or API keys. Includes a walkthrough example showing the learn-then-recall loop across two sessions and a tradeoffs section comparing Lite with Full Kaizen. --- KAIZEN_LITE.md | 152 ++++++++++++++++++ README.md | 1 + plugins/kaizen/README.md | 10 +- plugins/kaizen/skills/learn/SKILL.md | 6 +- .../skills/learn/scripts/save_entities.py | 10 +- plugins/kaizen/skills/recall/SKILL.md | 2 +- .../recall/scripts/retrieve_entities.py | 4 +- 7 files changed, 171 insertions(+), 14 deletions(-) create mode 100644 KAIZEN_LITE.md diff --git a/KAIZEN_LITE.md b/KAIZEN_LITE.md new file mode 100644 index 00000000..4e92b64b --- /dev/null +++ b/KAIZEN_LITE.md @@ -0,0 +1,152 @@ +# Kaizen Lite + +Kaizen Lite is a lightweight mode that runs as a Claude Code plugin — no vector store, no MCP servers, no API keys required. It stores entities as plain JSON in your project directory and uses Claude Code's built-in hooks to inject them automatically. + +## Prerequisites + +- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) installed with credentials configured + +## Installation + +### From Local Directory + +```bash +claude --plugin-dir /path/to/kaizen/repo/plugins/kaizen +``` + +### From Marketplace + +```bash +claude plugin marketplace add AgentToolkit/kaizen +claude plugin install kaizen@kaizen-marketplace +``` + +Verify the plugin is active: + +```bash +claude plugin list +``` + +## How It Works + +Kaizen Lite has two halves: + +1. **Learn** — You invoke `/kaizen:learn` at the end of a conversation. The plugin analyzes what happened and extracts reusable entities (preferences, strategies, recovery patterns) into `.kaizen/entities.json`. + +2. **Recall** — On every subsequent prompt, a `UserPromptSubmit` hook automatically loads stored entities and injects them into the conversation context. Claude applies whichever entities are relevant to the current task. + +No external services are involved. The entire loop is a JSON file and two Python scripts. + +## Example Walkthrough + +This example shows the full learn-then-recall loop across two sessions. + +### Session 1 — Learn a preference + +``` +You: Tell me the distances between the 3 most populous cities in Canada. + +Claude: The three most populous cities in Canada are Toronto, Montreal, and + Vancouver. Here are the distances between them: + + | City Pair | Distance (km) | Distance (miles) | + |--------------------------|---------------|------------------| + | Toronto ↔ Montreal | 541 | 336 | + | Toronto ↔ Vancouver | 4,338 | 2,695 | + | Montreal ↔ Vancouver | 4,810 | 2,989 | + +You: For cities in Canada use km only. + +Claude: Got it — I'll use kilometres only for Canadian cities. + +You: /kaizen:learn + +Claude: I've extracted the following entities from this conversation: + + { + "entities": [ + { + "content": "When presenting distances between Canadian cities, use kilometres only — do not include miles", + "rationale": "User explicitly prefers metric units for Canadian geography", + "category": "strategy", + "trigger": "When discussing distances or travel between cities in Canada" + } + ] + } + + Added 1 new entity(ies). Total: 1 + Entities stored in: /path/to/project/.kaizen/entities.json +``` + +### Session 2 — Preference is applied automatically + +Start a new Claude Code session in the same project: + +``` +You: Tell me the distances between the 3 most populous cities in Canada. + +Claude: The three most populous cities in Canada are Toronto, Montreal, and + Vancouver. Here are the distances between them: + + | City Pair | Distance (km) | + |--------------------------|---------------| + | Toronto ↔ Montreal | 541 | + | Toronto ↔ Vancouver | 4,338 | + | Montreal ↔ Vancouver | 4,810 | +``` + +The entity was automatically injected via the `UserPromptSubmit` hook, so Claude used kilometres only — without being reminded. + +## Available Skills + +| Skill | Description | +|-------|-------------| +| `/kaizen:learn` | Extract entities from the current conversation and save them | +| `/kaizen:recall` | Manually retrieve and display stored entities | +| `/kaizen:save` | Capture a successful workflow as a reusable skill | + +## Entities Storage + +Entities live in `.kaizen/entities.json` in the project root: + +```json +{ + "entities": [ + { + "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" + } + ] +} +``` + +Override the storage location with the `KAIZEN_ENTITIES_FILE` environment variable. + +## Tradeoffs + +Lite mode is easier to set up: + +- No vector DB +- No MCP servers +- No need to access agent logs or emit events to an observability tool +- No need to specify an LLM API key + +But it has a number of limitations: + +- **Inefficient context usage** — Entity extraction and recall both happen inside the agent's context window, not in a separate process. Full Kaizen offloads all processing to the MCP server, keeping the agent's context free for the actual task. +- **Scalability** — All entities are injected on every prompt. Full Kaizen uses semantic search to retrieve only the relevant subset, which scales to large entity sets. +- **Single-trajectory visibility** — Lite mode only extracts entities from the current session. Full Kaizen can ingest complete trajectories across multiple sessions and glean insights that a single-conversation view would miss. +- **Entity consolidation** — Lite mode simply appends new entities. Full Kaizen performs LLM-based conflict resolution to merge, supersede, or refine entities, and garbage-collects stale ones. + +| Capability | Kaizen Lite | Full Kaizen | +|------------|-------------|-------------| +| Entity storage | JSON file | Milvus vector store | +| Retrieval | All entities injected via hooks | Semantic search via MCP | +| Conflict resolution | Append-only | LLM-based merging + garbage collection | +| Trajectory analysis | Current session only (`/kaizen:learn`) | Multi-session, automatic via MCP | +| Context efficiency | Consumes main agent context | Processes separately via MCP | +| Observability | Not required | Ingests from agent logs / trace events | +| Infrastructure | None | MCP server + vector DB + API key | +| Setup time | < 1 minute | ~10 minutes | diff --git a/README.md b/README.md index fa144927..cd8a9309 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ npx @modelcontextprotocol/inspector@latest http://127.0.0.1:8201/sse --cli --met ## Documentation +- [KAIZEN_LITE.md](KAIZEN_LITE.md) - Lightweight mode via Claude Code plugin (no infra required) - [CONFIGURATION.md](CONFIGURATION.md) - Detailed configuration options - [CLI.md](CLI.md) - Command-line interface documentation - [CLAUDE_CODE_DEMO.md](CLAUDE_CODE_DEMO.md) - Claude Code demo walkthrough diff --git a/plugins/kaizen/README.md b/plugins/kaizen/README.md index 8d849b32..10eb9654 100644 --- a/plugins/kaizen/README.md +++ b/plugins/kaizen/README.md @@ -30,7 +30,7 @@ claude --plugin-dir /path/to/kaizen/repo/plugins/kaizen ### Entity Retrieval (Automatic) When you submit a prompt, the plugin automatically: -1. Loads all stored entities from `.claude/entities.json` +1. Loads all stored entities from `.kaizen/entities.json` 2. Formats and injects them into the conversation context 3. Claude applies relevant entities to the current task @@ -41,7 +41,11 @@ By default, you must manually invoke the `/kaizen:learn` skill to extract entiti 2. Invoke `/kaizen:learn` 3. The plugin analyzes the conversation trajectory 4. Extracts actionable entities from what worked/failed -5. Saves new entities to `.claude/entities.json` +5. Saves new entities to `.kaizen/entities.json` + +## Example Walkthrough + +See [KAIZEN_LITE.md](../../KAIZEN_LITE.md#example-walkthrough) for a step-by-step example showing the full learn-then-recall loop across two sessions. ## Skills Included @@ -74,7 +78,7 @@ User: "my-workflow-name" ## Entities Storage -Entities are stored in `.claude/entities.json`: +Entities are stored in `.kaizen/entities.json`: ```json { diff --git a/plugins/kaizen/skills/learn/SKILL.md b/plugins/kaizen/skills/learn/SKILL.md index 5117b3bd..8d48e423 100644 --- a/plugins/kaizen/skills/learn/SKILL.md +++ b/plugins/kaizen/skills/learn/SKILL.md @@ -78,7 +78,7 @@ python3 ${CLAUDE_PLUGIN_ROOT}/skills/learn/scripts/save_entities.py ``` The script will: -- Find or create the entities file (`.claude/entities.json`) +- Find or create the entities file (`.kaizen/entities.json`) - Merge new entities with existing ones (avoiding duplicates) - Display confirmation with the total count @@ -98,9 +98,9 @@ echo '{ **Output:** ```text -Creating new file: /path/to/project/.claude/entities.json +Creating new file: /path/to/project/.kaizen/entities.json Added 1 new entity(ies). Total: 1 -Entities stored in: /path/to/project/.claude/entities.json +Entities stored in: /path/to/project/.kaizen/entities.json ``` **Note:** Entities are also automatically saved when a conversation ends via the Stop hook. diff --git a/plugins/kaizen/skills/learn/scripts/save_entities.py b/plugins/kaizen/skills/learn/scripts/save_entities.py index 783521c1..5ff03ad9 100644 --- a/plugins/kaizen/skills/learn/scripts/save_entities.py +++ b/plugins/kaizen/skills/learn/scripts/save_entities.py @@ -52,9 +52,9 @@ def find_entities_file(): # Fall back to checking other candidate locations locations = [ # Project root from Claude Code - os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".claude/entities.json"), + os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".kaizen/entities.json"), # Current working directory - ".claude/entities.json", + ".kaizen/entities.json", # Plugin-relative path (fallback) str(Path(__file__).parent.parent / "entities.json"), ] @@ -71,10 +71,10 @@ def get_default_entities_path(): # Prefer project root if available project_root = os.environ.get("CLAUDE_PROJECT_ROOT", "") if project_root: - claude_dir = Path(project_root) / ".claude" + claude_dir = Path(project_root) / ".kaizen" else: - # Fall back to current directory's .claude/ - claude_dir = Path(".claude") + # Fall back to current directory's .kaizen/ + claude_dir = Path(".kaizen") claude_dir.mkdir(parents=True, exist_ok=True) return (claude_dir / "entities.json").resolve() diff --git a/plugins/kaizen/skills/recall/SKILL.md b/plugins/kaizen/skills/recall/SKILL.md index 08a7a992..139862ea 100644 --- a/plugins/kaizen/skills/recall/SKILL.md +++ b/plugins/kaizen/skills/recall/SKILL.md @@ -19,7 +19,7 @@ This skill retrieves relevant entities from a stored knowledge base based on the ## Entities Storage -Entities are stored in `.claude/entities.json` in the project root: +Entities are stored in `.kaizen/entities.json` in the project root: ```json { diff --git a/plugins/kaizen/skills/recall/scripts/retrieve_entities.py b/plugins/kaizen/skills/recall/scripts/retrieve_entities.py index f2f53eb8..34a84499 100644 --- a/plugins/kaizen/skills/recall/scripts/retrieve_entities.py +++ b/plugins/kaizen/skills/recall/scripts/retrieve_entities.py @@ -66,9 +66,9 @@ def find_entities_file(): # Fallback locations when KAIZEN_ENTITIES_FILE is not set locations = [ # Project root from Claude Code - os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".claude/entities.json"), + os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".kaizen/entities.json"), # Current working directory - ".claude/entities.json", + ".kaizen/entities.json", # Plugin-relative path (fallback) str(Path(__file__).parent.parent / "entities.json"), ] From 226a0808ecd6c453d5796df178f6042581ba1f27 Mon Sep 17 00:00:00 2001 From: Vinod Muthusamy Date: Mon, 23 Feb 2026 13:29:41 -0600 Subject: [PATCH 2/2] fix: clean up stale variable name and deduplicate entity file locations Rename claude_dir to kaizen_dir in save_entities.py to match the .kaizen directory, add text language specifier to KAIZEN_LITE.md fenced blocks, and guard CLAUDE_PROJECT_ROOT locations entry so it is only included when the env var is set (preventing a duplicate .kaizen/entities.json path). --- KAIZEN_LITE.md | 4 ++-- .../kaizen/skills/learn/scripts/save_entities.py | 14 ++++++++------ .../skills/recall/scripts/retrieve_entities.py | 6 ++++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/KAIZEN_LITE.md b/KAIZEN_LITE.md index 4e92b64b..f6db2bbd 100644 --- a/KAIZEN_LITE.md +++ b/KAIZEN_LITE.md @@ -43,7 +43,7 @@ This example shows the full learn-then-recall loop across two sessions. ### Session 1 — Learn a preference -``` +```text You: Tell me the distances between the 3 most populous cities in Canada. Claude: The three most populous cities in Canada are Toronto, Montreal, and @@ -82,7 +82,7 @@ Claude: I've extracted the following entities from this conversation: Start a new Claude Code session in the same project: -``` +```text You: Tell me the distances between the 3 most populous cities in Canada. Claude: The three most populous cities in Canada are Toronto, Montreal, and diff --git a/plugins/kaizen/skills/learn/scripts/save_entities.py b/plugins/kaizen/skills/learn/scripts/save_entities.py index 5ff03ad9..f702180e 100644 --- a/plugins/kaizen/skills/learn/scripts/save_entities.py +++ b/plugins/kaizen/skills/learn/scripts/save_entities.py @@ -50,14 +50,16 @@ def find_entities_file(): return Path(env_val).resolve() # Fall back to checking other candidate locations + project_root = os.environ.get("CLAUDE_PROJECT_ROOT") locations = [ - # Project root from Claude Code - os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".kaizen/entities.json"), # Current working directory ".kaizen/entities.json", # Plugin-relative path (fallback) str(Path(__file__).parent.parent / "entities.json"), ] + if project_root: + # Project root from Claude Code (prepend so it's checked first) + locations.insert(0, os.path.join(project_root, ".kaizen/entities.json")) for loc in locations: if loc and Path(loc).exists(): @@ -71,13 +73,13 @@ def get_default_entities_path(): # Prefer project root if available project_root = os.environ.get("CLAUDE_PROJECT_ROOT", "") if project_root: - claude_dir = Path(project_root) / ".kaizen" + kaizen_dir = Path(project_root) / ".kaizen" else: # Fall back to current directory's .kaizen/ - claude_dir = Path(".kaizen") + kaizen_dir = Path(".kaizen") - claude_dir.mkdir(parents=True, exist_ok=True) - return (claude_dir / "entities.json").resolve() + kaizen_dir.mkdir(parents=True, exist_ok=True) + return (kaizen_dir / "entities.json").resolve() def load_existing_entities(path): diff --git a/plugins/kaizen/skills/recall/scripts/retrieve_entities.py b/plugins/kaizen/skills/recall/scripts/retrieve_entities.py index 34a84499..034dfc95 100644 --- a/plugins/kaizen/skills/recall/scripts/retrieve_entities.py +++ b/plugins/kaizen/skills/recall/scripts/retrieve_entities.py @@ -64,14 +64,16 @@ def find_entities_file(): return path if path.exists() else None # Fallback locations when KAIZEN_ENTITIES_FILE is not set + project_root = os.environ.get("CLAUDE_PROJECT_ROOT") locations = [ - # Project root from Claude Code - os.path.join(os.environ.get("CLAUDE_PROJECT_ROOT", ""), ".kaizen/entities.json"), # Current working directory ".kaizen/entities.json", # Plugin-relative path (fallback) str(Path(__file__).parent.parent / "entities.json"), ] + if project_root: + # Project root from Claude Code (prepend so it's checked first) + locations.insert(0, os.path.join(project_root, ".kaizen/entities.json")) for loc in locations: if loc and Path(loc).exists(): return Path(loc)