Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ __pycache__
kaizen_data
demo/workdir/.claude/
.claude
dist
36 changes: 36 additions & 0 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,38 @@ kaizen entities show my_namespace 12345
kaizen entities delete my_namespace 12345
```

### Skill Management

```bash
# Package all skills from default location (plugins/kaizen/skills → dist/)
kaizen skills package

# Preview what would be packaged (no files created)
kaizen skills package --dry-run

# Package from a custom source directory
kaizen skills package --source ./my-skills

# Package to a custom output directory
kaizen skills package --output ./dist

# Remove existing .skill files before packaging
kaizen skills package --clean

# Combine options
kaizen skills package --source ./my-skills --output ./dist --clean
```

**Options:**
- `--source, -s`: Source directory containing skill folders (default: `plugins/kaizen/skills`)
- `--output, -o`: Output directory for `.skill` files (default: `dist`)
- `--clean`: Remove existing `.skill` files in output directory before packaging
- `--dry-run`: Show what would be packaged without creating files

**Skill Requirements:**
- Each skill must be a directory containing a `SKILL.md` file
- The resulting `.skill` file is a ZIP archive with the skill directory as the top-level folder

## Examples

```bash
Expand All @@ -84,6 +116,10 @@ uv run kaizen entities search coding_guidelines "error handling"

# List all guidelines
uv run kaizen entities list coding_guidelines --type guideline

# Package skills for distribution
uv run kaizen skills package --dry-run # Preview first
uv run kaizen skills package --clean # Package with clean output
```

## Environment Variables
Expand Down
99 changes: 99 additions & 0 deletions kaizen/cli/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""Kaizen CLI for managing entities and namespaces."""

import json
import sys
import zipfile
from pathlib import Path
from typing import Annotated, Optional

import typer
Expand All @@ -19,10 +22,12 @@
namespaces_app = typer.Typer(help="Namespace management commands")
entities_app = typer.Typer(help="Entity management commands")
sync_app = typer.Typer(help="Sync commands")
skills_app = typer.Typer(help="Skill management commands")

app.add_typer(namespaces_app, name="namespaces")
app.add_typer(entities_app, name="entities")
app.add_typer(sync_app, name="sync")
app.add_typer(skills_app, name="skills")

console = Console()

Expand Down Expand Up @@ -374,5 +379,99 @@ def sync_phoenix(
raise typer.Exit(1)


# =============================================================================
# Skills Commands
# =============================================================================


@skills_app.command("package")
def package_skills(
source: Annotated[Path, typer.Option("--source", "-s", help="Source skills directory")] = Path("plugins/kaizen/skills"),
output: Annotated[Path, typer.Option("--output", "-o", help="Output directory for .skill files")] = Path("dist"),
clean: Annotated[bool, typer.Option("--clean", help="Remove existing .skill files before packaging")] = False,
dry_run: Annotated[bool, typer.Option("--dry-run", help="Show what would be packaged without creating files")] = False,
):
"""Package plugin skills into .skill files for distribution."""
# Validate source directory
if not source.exists():
console.print(f"[red]Source directory not found: {source}[/red]")
raise typer.Exit(1)

if not source.is_dir():
console.print(f"[red]Source is not a directory: {source}[/red]")
raise typer.Exit(1)

# Find valid skill directories (those containing SKILL.md)
skill_dirs: list[tuple[str, Path]] = []
for item in sorted(source.iterdir()):
if item.is_dir():
skill_md = item / "SKILL.md"
if skill_md.exists():
skill_dirs.append((item.name, item))

if not skill_dirs:
console.print(f"[yellow]No skills found in {source}[/yellow]")
console.print("[dim]Skills must contain a SKILL.md file[/dim]")
raise typer.Exit(0)

# Display found skills
console.print(f"[bold]Found {len(skill_dirs)} skill(s) in {source}[/bold]\n")

table = Table(title="Skills to Package")
table.add_column("Skill", style="cyan")
table.add_column("Files", justify="right")
table.add_column("Output", style="dim")

for skill_name, skill_path in skill_dirs:
file_count = sum(1 for _ in skill_path.rglob("*") if _.is_file())
output_file = output / f"{skill_name}.skill"
table.add_row(skill_name, str(file_count), str(output_file))

console.print(table)
console.print()

if dry_run:
console.print("[yellow]Dry run - no files created[/yellow]")
return

# Create output directory if needed
output.mkdir(parents=True, exist_ok=True)

# Clean existing .skill files if requested
if clean:
existing_skills = list(output.glob("*.skill"))
if existing_skills:
console.print(f"[dim]Removing {len(existing_skills)} existing .skill file(s)...[/dim]")
for skill_file in existing_skills:
skill_file.unlink()

# Package each skill
packaged = 0
failed = 0
for skill_name, skill_path in skill_dirs:
output_file = output / f"{skill_name}.skill"

try:
with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf:
for file_path in skill_path.rglob("*"):
if file_path.is_file():
# Archive path includes skill name as top-level directory
arcname = f"{skill_name}/{file_path.relative_to(skill_path)}"
zf.write(file_path, arcname)

console.print(f"[green]Packaged:[/green] {skill_name} -> {output_file}")
packaged += 1

except (OSError, PermissionError, zipfile.LargeZipFile, zipfile.BadZipFile, ValueError) as e:
console.print(f"[red]Failed to package {skill_name}: {e}[/red]")
failed += 1

if failed == 0:
console.print(f"\n[bold green]Successfully packaged {packaged}/{len(skill_dirs)} skill(s)[/bold green]")
else:
console.print(f"\n[bold yellow]Packaged {packaged}/{len(skill_dirs)} skill(s); {failed} failed[/bold yellow]")
sys.exit(1)


if __name__ == "__main__":
app()
4 changes: 2 additions & 2 deletions plugins/kaizen/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"name": "kaizen",
"version": "1.0.0",
"description": "Learn from conversations with auto-generated guidelines",
"description": "Learn from conversations with auto-generated entities",
"author": {
"name": "Vinod Muthusamy"
},
"skills": "./skills/"
}
}
53 changes: 26 additions & 27 deletions plugins/kaizen/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Guidelines Plugin for Claude Code
# Kaizen Plugin for Claude Code

A plugin that helps Claude Code learn from conversations by automatically extracting and applying guidelines.
A plugin that helps Claude Code learn from conversations by automatically extracting and applying entities.

## Features

- **Automatic Retrieval**: At the start of each prompt, relevant guidelines are automatically injected
- **Manual Learning**: Use the `/kaizen:learn` skill to extract and save guidelines from conversations
- **Automatic Retrieval**: At the start of each prompt, relevant entities are automatically injected
- **Manual Learning**: Use the `/kaizen:learn` skill to extract and save entities from conversations
- **Zero-config Retrieval**: Hooks are automatically installed when the plugin is enabled

## Installation
Expand All @@ -27,34 +27,34 @@ claude --plugin-dir /path/to/kaizen/repo/plugins/kaizen

## How It Works

### Guideline Retrieval (Automatic)
### Entity Retrieval (Automatic)

When you submit a prompt, the plugin automatically:
1. Loads all stored guidelines from `.claude/guidelines.json`
1. Loads all stored entities from `.claude/entities.json`
2. Formats and injects them into the conversation context
3. Claude applies relevant guidelines to the current task
3. Claude applies relevant entities to the current task

### Guideline Generation (Manual by Default)
### Entity Generation (Manual by Default)

By default, you must manually invoke the `/kaizen:learn` skill to extract guidelines:
By default, you must manually invoke the `/kaizen:learn` skill to extract entities:
1. Complete a conversation or task
2. Invoke `/kaizen:learn`
2. Invoke `/kaizen:learn`
3. The plugin analyzes the conversation trajectory
4. Extracts actionable guidelines from what worked/failed
5. Saves new guidelines to `.claude/guidelines.json`
4. Extracts actionable entities from what worked/failed
5. Saves new entities to `.claude/entities.json`

## Skills Included

### `/kaizen:learn`

Manually invoke to extract guidelines from the current conversation:
Manually invoke to extract entities from the current conversation:
- Analyzes task, steps taken, successes and failures
- Generates proactive guidelines (what to do, not what to avoid)
- Generates proactive entities (what to do, not what to avoid)
- Outputs JSON for storage

### `/kaizen:recall`

Manually invoke to retrieve and display stored guidelines.
Manually invoke to retrieve and display stored entities.

### `/kaizen:save`

Expand All @@ -72,15 +72,13 @@ Assistant: "What would you like to name this skill?"
User: "my-workflow-name"
```

See [SAVE_SKILL.md](SAVE_SKILL.md) for detailed documentation.
## Entities Storage

## Guidelines Storage

Guidelines are stored in `.claude/guidelines.json`:
Entities are stored in `.claude/entities.json`:

```json
{
"guidelines": [
"entities": [
{
"content": "Use Python PIL/Pillow for image metadata extraction in sandboxed environments",
"rationale": "System tools like exiftool may not be available",
Expand All @@ -93,8 +91,8 @@ Guidelines are stored in `.claude/guidelines.json`:

## Environment Variables

- `GUIDELINES_FILE`: Override the default guidelines storage location
- `CLAUDE_PROJECT_ROOT`: Set by Claude Code, used to locate project-level guidelines
- `KAIZEN_ENTITIES_FILE`: Override the default entities storage location
- `CLAUDE_PROJECT_ROOT`: Set by Claude Code, used to locate project-level entities

## Verification

Expand All @@ -108,16 +106,17 @@ kaizen/
│ └── plugin.json # Plugin manifest
├── skills/
│ ├── learn/
│ │ └── SKILL.md
│ │ ├── SKILL.md
│ │ └── scripts/
│ │ └── save_entities.py
│ ├── recall/
│ │ └── SKILL.md
│ │ ├── SKILL.md
│ │ └── scripts/
│ │ └── retrieve_entities.py
│ └── save/
│ └── SKILL.md
├── hooks/
│ └── hooks.json # Auto-configured hooks
├── scripts/
│ ├── save_guidelines.py
│ └── retrieve_guidelines.py
└── README.md
```

Expand Down
Loading