
minipainter
io.github.ArturSkowronskiPublished by GitHub account ArturSkowronskiv0.7.3Updated Oct 24, 2026
Local-first miniature-paint inventory and cross-brand color matching for AI agents.
Overview
A local-first miniature paint registry that lets an assistant search a bundled paint catalog, match colors across brands, and track which paints you own.
- What you can do
- Search and inspect paints in a bundled catalog of 1,607 paints across Citadel, Army Painter, Vallejo and AK, by name, role, family or approximate color, with owned-first results and RGB details per paint. Match a color or a description to the nearest paints, including cross-brand equivalents. List, mark owned and mark unowned paints in a local inventory file, so suggestions can favor paints you actually have. A colored terminal UI and CLI expose the same catalog and inventory outside the assistant.
- When to use it
- Useful for miniature painters who want an assistant to recommend paints from their own rack rather than random colors, or to find close matches between brands for a specific shade.
- Requirements
- Runs locally over stdio via npx (npm package minipainter) or from source; needs Node.js 18 or newer and a POSIX-like shell (Linux, macOS, WSL). The catalog is bundled, so no configuration is needed; the inventory defaults to ~/.minipainting/inventory.json and can be overridden with INVENTORY_PATH. No authentication is declared.
Installation
In SourceWeft
- Open minipainter in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
MINIPAINTER
The paint bench, indexed.
Site: arturskowronski.github.io/minipainter
minipainter is a local-first paint registry for miniature-painting workflows. It exists for one practical reason: AI paint suggestions are much more useful when they understand the paints you actually own.
The project gives you:
- a deterministic local catalog (1,607 paints across Citadel, Army Painter, Vallejo, AK) and inventory
- owned-first paint lookup and cross-brand color matching
- a colored terminal UI (TUI) that shows each paint's real RGB as a swatch
- MCP servers for both Claude Desktop and ChatGPT
- a CLI surface designed for both humans and agent workflows
The colored TUI
The ledger TUI is a real colored terminal app: a MINIPAINTER banner, gold section
frames, green OWNED / red MISSING status, and a truecolor swatch of every paint's own
RGB. Color turns on for a TTY and honors NO_COLOR.
[MINIPAINTER terminal UI — catalog]
Why This Exists
Most paint advice workflows break at the same point: they recommend paints you do not have on hand.
minipainter is built to solve that exact problem:
- keep a local record of what is in your paint rack
- search it quickly by name, role, family, and approximate color
- prepare a stable inventory foundation for a future AI skill that can inspect links, photos, and model images
The long-term goal is not “AI picks random colors for miniatures.” The goal is “AI reasons from your actual inventory first, then suggests stronger alternatives only when useful.”
Feature Highlights
Owned-first matching: lookups and recommendations can prioritize paints you already have.Catalog in repo, inventory in your home: paint records live indata/catalog/; what you own lives in~/.minipainting/inventory.jsonand follows you across projects.RGB-aware search: approximate RGB values help with nearest-color matching.Colored TUI: terminal ledger with per-paint RGB swatches and OWNED/MISSING status.Agent-friendly CLI: deterministic command output for AI integration (Claude + ChatGPT MCP).
Screenshots
Hero Screen
Full-screen TUI with banner, catalog, detail panel, and command strip.
Search View
Filtered lookup for a semantic search like bone.
Owned View
Inventory-only presentation focused on what is already bound to your collection.
CLI Flow
Representative command-line usage for search, ownership updates, and color matching.
Run with Docker (Postgres)
The whole stack — MCP/HTTP server plus a Postgres that stores your inventory — starts with
one command. Inventory persists in a named volume, so it survives container restarts and
docker compose down / recreation (only down -v wipes it).
GET /health— livenessGET /api/inventory— owned paints (from Postgres)POST /mcp— MCP for Claude Desktop ·POST /mcp/v3— MCP for ChatGPT (search/fetch)
Storage is selected by DATABASE_URL: set it (as docker-compose.yml does) for Postgres,
leave it unset to use a local JSON inventory file (unchanged local behavior). See .env.example.
Deploy
Any Docker + Postgres host works (Fly.io, Railway, a VPS…). For a one-click remote MCP
server with a managed database, the repo ships a Render Blueprint (render.yaml) that
provisions the web service and Postgres together and wires DATABASE_URL automatically:
The reference deployment warpaint-mcp.fly.dev runs on Fly.io with Fly Managed Postgres — see
docs/deploy-fly.md for the fly mpg attach + migration steps.
Install
The fastest way — run it straight from npm with npx, no clone, no install:
Or install it globally to get the short mpaint command everywhere:
The catalog is bundled, so search and matching work on first run with nothing to configure. Your inventory lives at ~/.minipainting/inventory.json, created automatically the first time you mark a paint owned (legacy ~/.warpaint/ is auto-migrated).
Requirements:
- Node.js 18 or newer
- POSIX-ish shell (Linux, macOS, WSL)
From source
To hack on it, clone and run against the working tree:
After that you have four usage modes:
- CLI / TUI — see Quickstart below
- Self-hosted HTTP server — a single Docker-friendly runtime with JSON storage and API endpoints
- Local MCP for Claude Desktop — see Claude Desktop MCP Setup
- Remote MCP for Claude mobile/web — see Remote MCP
Quickstart
Initialize the local inventory at ~/.minipainting/inventory.json:
Search paints:
Inspect one paint:
Mark paints as owned or missing:
Run semantic or color matching:
Launch the TUI:
Run the MCP server locally:
Run the self-hosted HTTP server locally:
TUI Workflow
The TUI is centered around three presentation areas:
FORGE CATALOG: visible paints in the current scopeSELECTED PIGMENT: the currently highlighted paint with provider, families, usage, and RGBRITUAL COMMANDS: the command legend for the active session
Current TUI commands:
search <text>ownedcatalogtogglequit
Recommended use:
- start with
catalog - narrow with
search bone,search black, or similar queries - inspect the selected pigment panel
- toggle ownership as your collection changes
Project Direction
Implemented now:
- local JSON registry
- starter provider catalogs for Citadel and Army Painter
- owned / missing inventory tracking
- deterministic search and color matching
- colored terminal presentation with per-paint swatches
- local MCP server for Claude Desktop
Planned later:
- a separate skill for parsing paint-set links
- image-driven inventory fill from paint bottle photos
- model-photo analysis that recommends owned paints first
- stronger cross-provider equivalents and matching hints
Technical Notes
- Built-in catalog data lives in
data/catalog/(Citadel and Army Painter, kept in version control) - Inventory file:
~/.minipainting/inventory.json— stores only owned paint ids in the form{ "version": 1, "owned": ["citadel/abaddon-black", ...] } - Self-hosted server data directory:
DATA_DIR(defaults to/datain Docker); inventory lives at<DATA_DIR>/inventory.json - The catalog and inventory are composed at runtime; saving never rewrites the catalog
- IDs are stable by convention (provider + name slug); on load, owned ids missing from the catalog are reported as warnings instead of being silently dropped
- A pre-existing project-local
.minipainting/registry.jsonnext to the inventory path is auto-migrated on first run - Legacy
.warpaint/data directories are auto-renamed to.minipainting/on first run (both home and project-local variants) - Override the inventory location at the API surface with
{ inventoryPath }or{ cwd }(the latter resolves to<cwd>/.minipainting/inventory.json, which is what the test suite uses for isolation) - RGB values are approximate reference colors for matching, not a guarantee of final painted appearance
- MCP entrypoint:
node src/mcp-server.mjs - MCP helper script:
npm run mcp - HTTP server helper script:
npm run server - README demo captures are reproducible via:
Claude Desktop MCP Setup
minipainter now includes a local MCP server so Claude Desktop can use your paint registry directly.
Example local MCP config:
After adding the server, Claude Desktop can call tools such as:
paint_searchpaint_showinventory_listinventory_mark_ownedinventory_mark_unownedmatch_colormatch_describe
Suggested local flow:
- initialize your registry once with
node src/cli.mjs catalog sync - add the MCP server to Claude Desktop
- ask Claude to search paints or update ownership through the exposed tools
Agent Skill
For Claude Code, fetch the skill straight from the site, no clone required. It ships with the
right guardrails baked in: JSON-only reads, product_format rules, failure handling.
Or save it to ~/.claude/skills/minipainter/SKILL.md to use it everywhere.
Self-Hosted Docker
The Docker image runs a single HTTP server runtime designed for self-hosted use. Build it from the repo (no image is published to a registry yet):
Or bring up the server together with Postgres in one step with docker compose up -d.
The server exposes:
GET /healthGET /api/paintsGET /api/paints/:paintGET /api/inventoryPUT /api/inventory/:paintDELETE /api/inventory/:paintPOST /api/match/colorPOST /api/match/describePOST /mcp
Optional runtime configuration:
PORT— listen port, defaults to3000DATA_DIR— persistent state directory, defaults to/datain DockerAUTH_TOKEN— protects/api/*and/mcpwithAuthorization: Bearer ...INVENTORY_SYNC_TOKEN— protects the legacy/inventorysync endpoint
Remote MCP (Claude Mobile)
For Claude mobile or web, the stdio MCP server above is not reachable. Run
minipainter-mcp-http instead — a Streamable HTTP MCP transport exposing the
same tools, plus GET/POST /inventory for syncing the local inventory.
Local smoke test
Then in another shell:
Deploy to Fly.io
The repo ships a Dockerfile and fly.toml. Full recipe in
docs/deploy-fly.md. Short version:
Connect Claude
In Claude (mobile or web), add a custom connector:
- URL:
https://<your-app-name>.fly.dev/mcp
The /mcp endpoint currently has no authentication — anyone with the URL can
call tools. Use the obscurity of the URL plus Fly's network controls for now;
add per-user auth before sharing the URL.
Environment variables
Known limitations
/mcphas no authentication yet. The bearer token only protects/inventory.- Stateless transport: no long-running SSE tool streams (the tools are fast so this is fine).
Self-hosting your own MCP
The MCP server is generic — only the CLI (mpaint) is branded. To run your
own instance:
-
Fork or clone the repo.
-
(Optional) rename your Fly app in
fly.toml. -
Create a Fly volume and set secrets:
-
(Optional) name your MCP server (shown in the MCP handshake and startup logs):
-
Deploy:
-
Register the remote in your local CLI and sync:
After this, your local inventory and the deployed MCP stay in sync via
mpaint sync push (upload local → remote) and mpaint sync pull --force
(overwrite local from remote).
License
MIT © Artur Skowronski
Source: README.md at commit fe3fd9b
Tools
0Version history
1- v0.7.3LatestSep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts