minipainter
About
Local-first miniature-paint inventory + cross-brand color matching for AI agents (Citadel, Army Painter, Vallejo, AK).
Details
- Author
- arturskowronski
- Categories
- Other, Database, Knowledge Base
Jump to
Setup
Install minipainter in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/arturskowronski/minipainter
Follow the installation instructions in the repository README, then restart your MCP client.
Site:arturskowronski.github.io/minipainter
minipainteris 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.
- 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 ledger TUI is a real colored terminal app: aMINIPAINTERbanner, gold section frames, greenOWNED/ redMISSINGstatus, and a truecolor swatch of every paint's own RGB. Color turns on for a TTY and honorsNO_COLOR.
Most paint advice workflows break at the same point: they recommend paints you do not have on hand.
minipainteris 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.”
- 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).
Full-screen TUI with banner, catalog, detail panel, and command strip.
Filtered lookup for a semantic search likebone.
Inventory-only presentation focused on what is already bound to your collection.
Representative command-line usage for search, ownership updates, and color matching.
The whole stack — MCP/HTTP server plus a Postgres that stores your inventory — starts with one command. Inventory persists in a named volume, so itsurvives container restarts anddocker compose down/ recreation(onlydown -vwipes it).
docker compose up --build # http://localhost:3000
- GET /health— liveness
- GET /api/inventory— owned paints (from Postgres)
- POST /mcp— MCP for Claude Desktop ·POST /mcp/v3— MCP for ChatGPT (search/fetch)
Storage is selected byDATABASE_URL: set it (asdocker-compose.ymldoes) for Postgres, leave it unset to use a local JSON inventory file (unchanged local behavior). See.env.example.
Any Docker + Postgres host works (Fly.io, Railway, a VPS…). For a one-click remote MCP server with a managed database, the repo ships aRender Blueprint(render.yaml) that provisions the web service and Postgres together and wiresDATABASE_URLautomatically:
The reference deploymentwarpaint-mcp.fly.devruns on Fly.io with Fly Managed Postgres — seedocs/deploy-fly.mdfor thefly mpg attach+ migration steps.
The fastest way — run it straight from npm withnpx, no clone, no install:
npx minipainter paint search bone npx minipainter match color "#d2c29b" npx minipainter tui
Or install it globally to get the shortmpaintcommand everywhere:
npm install -g minipainter mpaint paint search bone mpaint match color "#d2c29b"
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).
- Node.js 18 or newer
- POSIX-ish shell (Linux, macOS, WSL)
To hack on it, clone and run against the working tree:
git clone https://github.com/ArturSkowronski/minipainter.git cd minipainter npm install node src/cli.mjs paint search bone
- 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— seeClaude Desktop MCP Setup
- Remote MCP for Claude mobile/web— seeRemote MCP
Initialize the local inventory at~/.minipainting/inventory.json:
node src/cli.mjs paint search black node src/cli.mjs paint search bone --json
node src/cli.mjs paint show "Abaddon Black" --json
node src/cli.mjs inventory own "Abaddon Black" node src/cli.mjs inventory unown "Abaddon Black" node src/cli.mjs inventory list
node src/cli.mjs match describe bone node src/cli.mjs match color "#d2c29b"
Run the self-hosted HTTP server locally:
DATA_DIR=.minipainting-data node src/mcp-http-server.mjs
The TUI is centered around three presentation areas:
- FORGE CATALOG: visible paints in the current scope
- SELECTED PIGMENT: the currently highlighted paint with provider, families, usage, and RGB
- RITUAL COMMANDS: the command legend for the active session
- search <text>
- owned
- catalog
- toggle
- quit
- start withcatalog
- narrow withsearch bone,search black, or similar queries
- inspect the selected pigment panel
- toggle ownership as your collection changes
- 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
- 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
- Built-in catalog data lives indata/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:
minipainternow includes a local MCP server so Claude Desktop can use your paint registry directly.
{ "mcpServers": { "minipainter": { "command": "node", "args": ["/absolute/path/to/minipainter/src/mcp-server.mjs"] } } }
After adding the server, Claude Desktop can call tools such as:
- paint_search
- paint_show
- inventory_list
- inventory_mark_owned
- inventory_mark_unowned
- match_color
- match_describe
- initialize your registry once withnode src/cli.mjs catalog sync
- add the MCP server to Claude Desktop
- ask Claude to search paints or update ownership through the exposed tools
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_formatrules, failure handling.
# project-scoped mkdir -p .claude/skills/minipainter curl -fsSL https://arturskowronski.github.io/minipainter/SKILL.md \ -o .claude/skills/minipainter/SKILL.md
Or save it to~/.claude/skills/minipainter/SKILL.mdto use it everywhere.
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):
docker build -t minipainter . docker run -p 3000:3000 -v minipainting-data:/data minipainter
Or bring up the server together with Postgres in one step withdocker compose up -d.
- GET /health
- GET /api/paints
- GET /api/paints/:paint
- GET /api/inventory
- PUT /api/inventory/:paint
- DELETE /api/inventory/:paint
- POST /api/match/color
- POST /api/match/describe
- POST /mcp
- PORT— listen port, defaults to3000
- DATA_DIR— persistent state directory, defaults to/datain Docker
- AUTH_TOKEN— protects/api/*and/mcpwithAuthorization: Bearer ...
- INVENTORY_SYNC_TOKEN— protects the legacy/inventorysync endpoint
For Claude mobile or web, the stdio MCP server above is not reachable. Runminipainter-mcp-httpinstead — a Streamable HTTP MCP transport exposing the same tools, plusGET/POST /inventoryfor syncing the local inventory.
export INVENTORY_SYNC_TOKEN=$(openssl rand -hex 32) export PORT=3000 export INVENTORY_PATH=$HOME/.minipainting/inventory.json npm run mcp:http
curl -s http://localhost:3000/health curl -s -X POST http://localhost:3000/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # Sync endpoint (bearer-token protected) curl -s -H "Authorization: Bearer $INVENTORY_SYNC_TOKEN" \ http://localhost:3000/inventory
The repo ships aDockerfileandfly.toml. Full recipe indocs/deploy-fly.md. Short version:
fly launch --no-deploy --copy-config --name <your-app-name> fly volumes create inventory_data --region <your-region> --size 1 fly secrets set INVENTORY_SYNC_TOKEN="$(openssl rand -hex 32)" fly deploy
In Claude (mobile or web), add a custom connector:
- URL:https://<your-app-name>.fly.dev/mcp
The/mcpendpoint 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.
- /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).
The MCP server is generic — only the CLI (mpaint) is branded. To run your own instance:
(Optional) rename your Fly app infly.toml.
fly volumes create inventory_data --size 1 --region <your-region> fly secrets set INVENTORY_SYNC_TOKEN=$(openssl rand -hex 24) # Optional one-time seed: fly secrets set INVENTORY_JSON="$(cat ~/.minipainting/inventory.json)"
(Optional) name your MCP server (shown in the MCP handshake and startup logs):
fly secrets set MCP_SERVER_NAME=my-paints
Register the remote in your local CLI and sync:
mpaint sync add default \ --url https://my-app.fly.dev \ --token <token-from-step-3> mpaint sync push
After this, your local inventory and the deployed MCP stay in sync viampaint sync push(upload local → remote) andmpaint sync pull --force(overwrite local from remote).
Structured aquarium, marine, terrarium and paludarium data for AI agents.
Talk to your Hardcover library from any AI assistant.
Unified access to global medical terminologies: ICD-11, SNOMED CT, LOINC, RxNorm, MeSH. 27 tools for medical coding, terminology lookup, and crosswalk mappings.
Medical terminology intelligence for AI agents — ICD-10-CM lookup, MedDRA hierarchy and SOC mapping, RxNorm drug concepts, CTCAE v5.0 grading, and cross-terminology mapping.
Tracks movies you've watched and provides recommendations based on your preferences.
Deterministic industrial replacement engine with official catalogs and expert accuracy checks.
A Model Context Protocol (MCP) server exposing Taiwan healthcare datasets such as ICD-10 and drug information for AI agents.
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





