Skip to content
Closed
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
129 changes: 125 additions & 4 deletions KAIZEN_LITE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Kaizen Lite has two halves:

No external services are involved. The entire loop is a JSON file and two Python scripts.

## Example Walkthrough
## Example 1 — Learning a user preference

This example shows the full learn-then-recall loop across two sessions.

Expand Down Expand Up @@ -97,6 +97,127 @@ Claude: The three most populous cities in Canada are Toronto, Montreal, and

The entity was automatically injected via the `UserPromptSubmit` hook, so Claude used kilometres only — without being reminded.

## Example 2 — Learning from failure in a sandboxed environment

This example shows how Kaizen Lite helps an agent avoid dead ends it encountered in a previous session. The agent runs in a Docker sandbox where common system tools are not installed.

To run it, first build the Docker image:

```bash
just sandbox-build
```

Then run a task to extract metadata from an image:

```bash
just trace=true learn=true sandbox-prompt 'where was the photo @sample.jpg taken. use exif metadata'
```

When you the above, you will see that the agent hits some dead ends (exiftool not found, Pillow not installed), and that it learns guidelines to avoid them in the future (see `demo/workspace/.kaizen/entities.json`).

Run the same task again in a new session:

```bash
just trace=true sandbox-prompt 'where was the photo @sample.jpg taken. use exif metadata'
```

You will see that the agent now is more efficient, avoiding the dead ends it encountered in the previous session such as trying to use exiftool.

The instructions below walk you through the same example in interactive sessions.


### Session 1 — Solving the hard way

The user asks the agent to find where a photo was taken:

```text
You: Where was this photo taken? [sample.jpg]

Claude: I'll extract the GPS coordinates from the photo's EXIF metadata.

[runs: exiftool sample.jpg]

exiftool: command not found

Let me try using Python with Pillow instead.

[runs: python3 -c "from PIL import Image; ..."]

ModuleNotFoundError: No module named 'PIL'

I'll install Pillow first.

[runs: pip install Pillow]
[runs: python3 script to extract EXIF GPS via Pillow]

The photo was taken at:
- Latitude: 51.4936° N
- Longitude: 0.0376° E

This places it in Wapping, East London, UK.
Google Maps: https://www.google.com/maps?q=51.493608,0.037561
```

The agent got the right answer, but wasted two turns on dead ends (exiftool not found, Pillow not installed). Now the user runs `/kaizen:learn`:

```text
You: /kaizen:learn

Claude: I've extracted the following entities from this conversation:

{
"entities": [
{
"content": "Use Python stdlib (struct module) to manually parse JPEG
EXIF/GPS metadata when no external tools are available",
"rationale": "In sandboxed environments, neither system tools (exiftool)
nor third-party libraries (PIL/Pillow) may be installed.
Python stdlib is always available and sufficient for JPEG
binary parsing.",
"category": "strategy",
"trigger": "When extracting EXIF or GPS metadata from images in
containerized or sandboxed environments"
},
{
"content": "When system tools or pip packages are unavailable, check if
the task can be solved with Python stdlib before attempting
installs",
"rationale": "Binary parsing, HTTP requests (urllib), JSON, CSV, and many
common tasks are fully covered by stdlib. Attempting installs
in sandboxes wastes time and often fails silently.",
"category": "recovery",
"trigger": "When a required CLI tool or Python package is missing in a
restricted environment"
}
]
}

Added 2 new entity(ies). Total: 2
Entities stored in: /workspace/.kaizen/entities.json
```

### Session 2 — No more dead ends

In a new session, the user asks the same question. The stored entities are automatically injected via the `UserPromptSubmit` hook:

```text
You: Where was this photo taken? [sample.jpg]

Claude: I'll extract the GPS coordinates from the EXIF data using Python's
struct module.

[runs: python3 script using struct to parse JPEG EXIF binary data]

The photo was taken at:
- Latitude: 51.4936° N
- Longitude: 0.0376° E

This places it in Wapping, East London, UK.
Google Maps: https://www.google.com/maps?q=51.493608,0.037561
```

The agent skipped both `exiftool` and `Pillow` entirely — it went straight to the Python stdlib approach that it learned works in sandboxed environments. Two wasted turns eliminated.

## Available Skills

| Skill | Description |
Expand All @@ -113,10 +234,10 @@ Entities live in `.kaizen/entities.json` in the project root:
{
"entities": [
{
"content": "Use Python PIL/Pillow for image metadata extraction in sandboxed environments",
"rationale": "System tools like exiftool may not be available",
"content": "Use Python stdlib (struct module) to manually parse JPEG EXIF/GPS metadata when no external tools are available",
"rationale": "In sandboxed environments, neither system tools (exiftool) nor third-party libraries (PIL/Pillow) may be installed. Python stdlib is always available.",
"category": "strategy",
"trigger": "When extracting image metadata in containerized environments"
"trigger": "When extracting EXIF or GPS metadata from images in containerized or sandboxed environments"
}
]
}
Expand Down
Binary file added demo/workspace/sample.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
58 changes: 58 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Default: list available targets
default:
@just --list

image := "claude-sandbox"
env_file := "sandbox/myenv"
sandbox_dir := "sandbox"
workspace := "demo/workspace"
trace := "false"
learn := "false"

# Build the sandbox Docker image
sandbox-build:
docker build -t {{image}} {{sandbox_dir}}

# Copy sample.env to myenv if it doesn't already exist
sandbox-setup:
@if [ ! -f {{env_file}} ]; then \
cp sandbox/sample.env {{env_file}}; \
echo "Created {{env_file}} — edit it and set your ANTHROPIC_API_KEY"; \
else \
echo "{{env_file}} already exists, skipping"; \
fi

# Run an interactive Claude Code shell in the sandbox
sandbox-run:
docker run --rm -it --env-file {{env_file}} -v "$(cd {{workspace}} && pwd)":/workspace -v "$(pwd)/plugins":/plugins {{image}}

# Run a one-shot prompt in the sandbox (trace=true to summarize session, learn=true to run /kaizen:learn)
sandbox-prompt prompt:
#!/usr/bin/env sh
TRACE_CMD=""
LEARN_CMD=""
if [ "{{trace}}" = "true" ]; then
TRACE_CMD="
echo; echo; echo Summarizing the session...; echo
claude --plugin-dir /plugins/kaizen/ --dangerously-skip-permissions --no-session-persistence -p 'tell me what happened in the newest json file in /home/sandbox/.claude/projects/-workspace/'
"
fi
if [ "{{learn}}" = "true" ]; then
LEARN_CMD="
echo; echo; echo Learning...; echo
claude --plugin-dir /plugins/kaizen/ --dangerously-skip-permissions --continue -p '/kaizen:learn'
"
fi
docker run --rm -it --env-file {{env_file}} -v "$(cd {{workspace}} && pwd)":/workspace -v "$(pwd)/plugins":/plugins {{image}} sh -c "
claude --plugin-dir /plugins/kaizen/ --dangerously-skip-permissions -p '{{prompt}}'
$TRACE_CMD
$LEARN_CMD
"

# Smoke-test that Claude Code is installed and working
sandbox-test:
docker run --rm --env-file {{env_file}} {{image}} claude -p "who are you"
Comment on lines +53 to +54

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 | 🟡 Minor

Add a timeout to the smoke-test to prevent indefinite blocking.

If the Claude API call hangs (network issue, bad key, etc.) this target blocks forever, which is especially problematic in CI. Using timeout (GNU coreutils) keeps the test bounded.

🐛 Proposed fix
-    docker run --rm --env-file {{env_file}} {{image}} claude -p "who are you"
+    docker run --rm --env-file {{env_file}} {{image}} timeout 30 claude -p "who are you"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
sandbox-test:
docker run --rm --env-file {{env_file}} {{image}} claude -p "who are you"
sandbox-test:
docker run --rm --env-file {{env_file}} {{image}} timeout 30 claude -p "who are you"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@justfile` around lines 27 - 28, The sandbox-test justfile target can block
indefinitely if the Claude API call hangs; wrap the Docker run invocation in a
timeout (e.g., GNU coreutils timeout) so the target exits after a bounded period
(choose a sensible value like 30–60s) and return a non-zero status on timeout;
update the sandbox-test target that currently runs `docker run --rm --env-file
{{env_file}} {{image}} claude -p "who are you"` to invoke it via timeout so CI
won't hang.


# Remove the sandbox Docker image
sandbox-clean:
docker rmi {{image}}
Comment on lines +57 to +58

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 | 🟡 Minor

docker rmi fails when stopped containers still reference the image.

After a sandbox-run session the stopped container keeps a reference to the image; a subsequent sandbox-clean errors out with "image is being used by stopped container". Adding -f (or --force) handles this gracefully for a local dev workflow.

🐛 Proposed fix
-    docker rmi {{image}}
+    docker rmi -f {{image}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@justfile` around lines 31 - 32, The sandbox-clean target currently runs
"docker rmi {{image}}" which fails if stopped containers still reference the
image; update the sandbox-clean target to force-remove the image by adding the
force flag (e.g., change docker rmi {{image}} to use -f/--force) so the command
will remove images even when referenced by stopped containers.

2 changes: 2 additions & 0 deletions sandbox/sample.env
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
ANTHROPIC_API_KEY=sk-ant-xxxx
KAIZEN_DEBUG=1
IS_SANDBOX=1