furnish is a Bun-powered CLI that turns construction photos into staged, fully furnished visuals. It orchestrates image generation models (via OpenRouter) in small subtasks (floors → doors → kitchen → furniture → lighting → windows) because large multi-step prompts tend to fail. Floorplans are mandatory; material references are strongly encouraged.
Image generation models like Gemini struggle with complex multi-step instructions. furnish addresses this by:
- Planning: Breaking your task into ordered subtasks using a cheap/fast model
- Executing: Running each subtask one at a time against the image model
- Verifying: Checking each result (auto or human-in-loop) before continuing
- Resuming: Saving state so you can pick up where you left off
- Interior-design-first: Built-in steps for floors, doors, kitchen, furniture, lighting, windows
- Reference management: Tag materials by category (floors, tiles, lamps, furniture, kitchen, windows, misc)
- Floorplan-required: Ensures spatial consistency across all transformations
- Two modes:
human(review each step) orauto(model-based verification) - Local image serving: Uses Serveo.net SSH tunneling to expose images to APIs without uploads
- Run persistence: Full manifest of each run with resume support
macOS (Apple Silicon):
curl -fsSL https://github.com/NicolaiSchmid/furnish-cli/releases/latest/download/furnish-darwin-arm64 -o furnish
chmod +x furnish
sudo mv furnish /usr/local/bin/Linux (x64):
curl -fsSL https://github.com/NicolaiSchmid/furnish-cli/releases/latest/download/furnish-linux-x64 -o furnish
chmod +x furnish
sudo mv furnish /usr/local/bin/Prerequisites: Bun >= 1.2
git clone https://github.com/NicolaiSchmid/furnish-cli.git
cd furnish-cli
bun install
bun run compile # outputs dist/furnish
./dist/furnish --helpbun run src/cli.ts init # configure API keys
bun run src/cli.ts --help # see all commandsRun the one-time setup to configure your API key:
furnish initThis creates ~/.config/furnish/config.json with your OpenRouter API key. Get one at https://openrouter.ai/keys
You can also set the API key via environment variable:
export OPENROUTER_API_KEY="sk-or-..."All other paths are local to your project directory:
./plan.yml- Generated plan file./runs/- Run outputs and manifests./references/- Reference images by category
References are saved to ./references/<category>/:
# List suggested categories
furnish references list
# Search and download references (opens browser, saves to ./references/)
furnish references fetch floors "light oak herringbone parquet"
furnish references fetch furniture "scandinavian living room sofa"
furnish references fetch lamps "modern pendant light"Creates ./plan.yml by default:
furnish plan \
--task "Transform this construction photo into a modern furnished apartment" \
--photo ./photos/construction.png \
--floorplan ./photos/floorplan.png \
--reference floors:./references/floors/oak.jpg \
--reference furniture:./references/furniture/sofa.jpgOutputs go to ./runs/<runId>/:
# Human-in-the-loop mode (review each step)
furnish run --plan ./plan.yml --mode human
# Auto mode (model verifies each step)
furnish run --plan ./plan.yml --mode auto
# Mock mode (test pipeline without API calls)
furnish run --plan ./plan.yml --mockResume and inspect work on runs in ./runs/:
# Resume a paused or failed run
furnish resume 20250125-143011-abc123
# Resume from a specific step (resets step 2 and all later steps)
furnish resume 20250125-143011-abc123 --from-step 2
# Inspect run status
furnish inspect 20250125-143011-abc123# 1. One-time setup (configures API key)
furnish init
# 2. Create a project directory
mkdir my-apartment && cd my-apartment
# 3. Gather references (saved to ./references/)
furnish references fetch floors "warm oak hardwood"
furnish references fetch kitchen "white modern cabinets marble countertop"
furnish references fetch furniture "minimalist scandinavian"
# 4. Create a plan (outputs ./plan.yml)
furnish plan \
--task "Turn this construction site into a move-in ready 2BR apartment" \
--photo ./living-room.png \
--floorplan ./floorplan.png \
--reference floors:./references/floors/oak.jpg \
--reference kitchen:./references/kitchen/cabinets.jpg \
--reference furniture:./references/furniture/sofa.jpg
# 5. Execute the plan (outputs to ./runs/<runId>/)
furnish run --plan ./plan.yml --mode human
# 6. If needed, resume from step 2
furnish resume <runId> --from-step 2src/
├── cli.ts # Command definitions (commander)
├── constants.ts # Reference categories, defaults
├── config/ # Config schema and loader
├── assets/ # Image collection, serving (Serveo tunneling), downloading
├── planner/ # Task decomposition (Flash 3 or heuristic)
├── engine/ # Image generation (OpenRouter/Gemini)
├── checker/ # Auto (Flash 3) and human verification
├── state/ # Run manifests, persistence
└── run/ # Orchestration loop
By default, furnish uses OpenRouter to access models:
- Image generation:
google/gemini-3-pro-image-preview- Gemini with image output - Planning/checking:
google/gemini-3-flash-preview- Fast, cheap text model
You can change these in the config or use any OpenRouter-compatible model.
- GitHub Actions for cross-platform binary releases
- Homebrew formula
- Image preview in terminal for human review
- More reference categories (wall finishes, art, appliances)
- Batch processing for multiple photos
- Direct base64 upload option (skip tunneling)