User Guide: Flavors and Overlays¶
This guide explains how to use pre-built flavors and create custom overlays to extend Nyia Keeper assistants with additional tools and packages.
Quick Decision: Flavor or Overlay?¶
| I need... | Use | Command |
|---|---|---|
| Python dev tools (pytest, black, mypy) | Flavor | nyia-claude --flavor python |
| PHP dev tools (PHPUnit, PHPStan) | Flavor | nyia-claude --flavor php |
| Node.js / React / Cypress / Expo | Flavor | nyia-claude --flavor node |
| PHP + React fullstack | Flavor | nyia-claude --flavor php-react |
| Rust + Tauri v2 desktop apps | Flavor | nyia-claude --flavor rust-tauri |
| Something else (custom packages) | Overlay | Create Dockerfile, then --build-custom-image |
Rule of thumb: - Flavor = ready to use, no build required - Overlay = custom, requires Docker and building
Part 1: Using Pre-built Flavors¶
Flavors are specialized images pre-built with common development tools. They're pulled automatically from the registry - no local build required.
List Available Flavors¶
Current Flavors¶
| Flavor | Tools Included |
|---|---|
python |
pytest, pytest-cov, black, mypy, ruff, isort, ipython |
php |
PHP 8.3, Composer, PHPUnit, PHPStan, PHP-CS-Fixer |
node |
Node.js 22, yarn, pnpm, typescript, biome, vitest, vite, storybook, cypress (headless Chromium), Expo (via npx expo), eas-cli |
php-react |
PHP 8.2 + React + Storybook + Jest + Cypress + PHPUnit (fullstack) |
rust-tauri |
Rust, Cargo, Tauri v2 CLI, clippy, rustfmt, cargo-watch, Node.js 22 |
Using a Flavor¶
# Python development
nyia-claude --flavor python
# PHP development
nyia-claude --flavor php
# Interactive mode with flavor
nyia-claude --flavor python
The first time you use a flavor, it will be pulled from the registry automatically.
Part 2: Creating Custom Overlays¶
If you need packages not included in any flavor, create a custom overlay.
Requirements: Docker must be installed.
Step 1: Create Your Overlay Dockerfile¶
Choose one of these locations:
| Location | Scope |
|---|---|
~/.config/nyiakeeper/claude/overlay/Dockerfile |
All your projects |
.nyiakeeper/claude/overlay/Dockerfile |
This project only |
Create your Dockerfile:
mkdir -p ~/.config/nyiakeeper/claude/overlay/
cat > ~/.config/nyiakeeper/claude/overlay/Dockerfile << 'EOF'
ARG BASE_IMAGE
FROM ${BASE_IMAGE}
# Install system packages (as root)
USER root
RUN apt-get update && apt-get install -y \
your-package \
another-package \
&& rm -rf /var/lib/apt/lists/*
# Install user packages (as node)
USER node
RUN pip install --no-cache-dir your-python-package
EOF
Step 2: Build Your Custom Image¶
nyia-claude --build-custom-image
# Force rebuild without Docker cache
nyia-claude --build-custom-image --no-cache
This creates a project-scoped image named nyiakeeper/claude-custom-{project} (e.g., nyiakeeper/claude-custom-my-app).
If only a user overlay exists (no project overlay), the global name nyiakeeper/claude-custom is used instead.
Step 3: Use Your Custom Image¶
# The build output shows the exact image name to use
nyia-claude --image nyiakeeper/claude-custom-my-app
Note: You must use --image to select your custom image. Without it, the default image is used.
Migration: Users who built legacy custom images (
nyiakeeper/claude-custom) before project scoping can still reference them via the--imageflag.
Step 4: Rebuild After an Update¶
Your custom image is built on top of the base image as it was at build time. When the base changes
(nyia update pulled a new image, or you pulled or rebuilt it yourself), the custom image keeps the
old base, with the old skills, prompts and tools, until you rebuild it:
nyia-claude --build-custom-image # for --flavor custom
nyia-claude --build-custom-image --flavor php # for --flavor php-custom
You do not need to remember this: every --flavor custom / --flavor <base>-custom launch compares
the custom image with its base and warns when the base has moved (see
Custom image built from an older base). The launch still
starts; nothing is rebuilt for you. A launch with --image <name> runs the image you named, with no check.
Overlay Stacking¶
If you have overlays in both locations, they're applied in order:
- Base image (from registry)
- User overlay (
~/.config/nyiakeeper/claude/overlay/) - Project overlay (
.nyiakeeper/claude/overlay/)
This allows global preferences plus project-specific additions.
Dockerfile Best Practices¶
Always Switch Users Properly¶
USER root
# Install system packages here
RUN apt-get update && apt-get install -y package
USER node
# Install user packages here
RUN pip install package
Clean Up Package Caches¶
Use --no-cache-dir for pip¶
Don't Override the Entrypoint¶
The base image has a configured entrypoint. Don't change it unless you know what you're doing.
Troubleshooting¶
"Flavor not found"¶
Solution: Check available flavors with --list-flavors. Did you mean node instead of nodejs?
"Cannot pull image"¶
Solutions:
- Check your network connection
- Try docker login ghcr.io if authentication is required
- Verify the image exists: docker manifest inspect ghcr.io/kaizendofr/nyiakeeper-claude-python:latest
Build fails with permission error¶
Solution: Make sure you switch to USER node before installing user packages, and USER root for system packages.
Custom image not found¶
❌ Custom image not found locally: nyiakeeper/claude-custom-myproject:latest
❌ Build it first: nyia-claude --build-custom-image
❌ Or run it explicitly: nyia-claude --image nyiakeeper/claude-custom-myproject:latest
❌ Custom images are project-scoped: this name belongs to project 'myproject' — an image built in a different project directory uses a different tag
Solution: Run the command the error suggests — --build-custom-image builds the image for
this project. Custom image names are project-scoped: a slug from the project folder name is
appended only when that project has its own .nyiakeeper/<assistant>/overlay/Dockerfile. An image
you built in another directory therefore has a different tag and will not be found here. List what
you actually have with nyia-claude --list-images (note the leading --).
For a based custom flavor (e.g. php-custom) the build line names the base instead: nyia-claude --build-custom-image --flavor php.
Custom image built from an older base¶
⚠️ Custom image nyiakeeper/claude-custom:latest was built from an older base
⚠️ base nyiakeeper/claude:latest: built on 3f1c9a2b7d40, now 9e02b4c1a8f3
⚠️ rebuild it to get the updated base: nyia-claude --build-custom-image
⚠️ (launching the current custom image anyway)
Meaning: the base image was updated after you built your custom image (typically by nyia update),
so the session runs the previous base. The two short ids are the base image the custom image was built
on and the one you have now.
Solution: run the rebuild command from the message. The next launch is silent again.
After nyia update the base usually has a new version tag, so the warning names the two images instead:
⚠️ Custom image nyiakeeper/claude-custom:latest was built on a different base than this launcher uses
⚠️ built on: ghcr.io/kaizendofr/nyiakeeper-claude:v0.1.0-beta.16
⚠️ launcher uses: ghcr.io/kaizendofr/nyiakeeper-claude:v0.1.0-beta.17
⚠️ rebuild it to get the current base: nyia-claude --build-custom-image
⚠️ (launching the current custom image anyway)
The same warning appears after a channel switch (for example alpha to beta). The fix is the same rebuild.
Two related one-line hints:
... has no base record (built before base tracking); rebuild it once ...: the image was built by an older Nyia Keeper that did not record its base. Rebuild it once; from then on base updates are detected.... is based on <old ref>; this launcher now uses <new ref>: the base comes from another repository or registry than before (for example a customNYIA_REGISTRY). Rebuild if you want the custom image on the new base.
--build-custom-image reads the current base image; if it is not on your machine it is pulled first, and
the build stops with an error when it cannot be pulled.
Quick Reference¶
| Task | Command |
|---|---|
| List flavors | nyia-claude --list-flavors |
| Use Python flavor | nyia-claude --flavor python |
| Use PHP flavor | nyia-claude --flavor php |
| Build custom overlay | nyia-claude --build-custom-image |
| Rebuild without cache | nyia-claude --build-custom-image --no-cache |
Rebuild after nyia update |
nyia-claude --build-custom-image [--flavor <base>] |
| Use custom image | nyia-claude --image nyiakeeper/claude-custom-my-app |
| Check available images | nyia-claude --list-images |