Rafiki is a local-first workflow for AI image generation, batch prompt runs, reviewing outputs in a browser, and rendering HTML to PNG.
It combines:
- a Node CLI entry point:
rafikiand the legacy aliasimage-gen - a Python generation engine for Gemini and OpenAI image models
- a local review portal for comparing runs, rating outputs, and browsing a project library
- a Puppeteer-based HTML-to-image renderer for cards, diagrams, and slide art
Rafiki is designed to run from a checkout on your machine. Your API keys stay local. There is no hosted Rafiki service.
Rafiki is ready for real work. The recommended install path is: clone the repo, install dependencies, run locally. Roadmap: docs/ROADMAP.md. The current public use-case focus is the keynote visual workflow: turning talk notes into prompt packs, reviewable image candidates, slide assets, and downstream web or social artifacts.
- Generate single images from a prompt
- Run batches from Markdown prompt files
- Keep every batch in an isolated
run-*directory - Rebuild viewers without re-running generation
- Review outputs in a local comparison viewer and library
- Rate images as starred, rejected, or unreviewed
- Render HTML files to PNG with Puppeteer
- Register image outputs from other directories on disk
- Export approved assets for downstream workflows
Rafiki requires Node.js 22.13+ with npm 10+ and Python 3.11+.
git clone https://github.com/WalksWithASwagger/rafiki.git
cd rafiki
npm ci
npm --prefix frontend ci
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
python -m pip install -r requirements-dev.txtThe ranged source requirements support local cross-platform installation. CI
instead installs the reviewed, hashed requirements-ci.txt graph compiled for
CPython 3.11 on Linux x86_64. Maintainers refresh it with
npm run lock:python-ci; it is not a universal user lock.
Rafiki commits .env.schema as the agent-readable environment contract. Keep
real values in your shell environment, an untracked repo-local value file, or
the user-managed shared directory at ~/.agents/env/values/. Agents validate
the contract without reading any value file directly.
The schema optionally imports reusable provider credentials from
.env.shared.local, followed by .env.rafiki.local for repo-specific
overrides. Both imports use pick allowlists and allowMissing=true, so Rafiki
keeps its own declarations authoritative and cloud or CI checks do not depend
on this Mac. The imported allowlist is limited to GOOGLE_API_KEY,
OPENAI_API_KEY, FLOYO_KEY, REPLICATE_API_TOKEN, and NOTION_API_KEY.
Portal credentials, Notion database IDs, executable paths, and Rafiki-only
settings remain app-local.
The shared directory and value files are created and maintained by the user,
not by agents. The canonical directory is mode 0700; .env.shared.local and
optional .env.<repo-slug>.local files are mode 0600.
cp .env.example .envAdd at least one of:
GOOGLE_API_KEYfor Gemini modelsOPENAI_API_KEYfor OpenAI image models
Varlock is intentionally kept outside Rafiki's Node dependency graph. Run Varlock 1.10 with Rafiki's Node 22.13+ runtime or use the standalone CLI, then inspect and audit the contract safely:
npm run env:validate
npm run env:audit
npm run env:scan
npm run env:smoke
python3 -m pytest -q tests/test_varlock_contract.pyThe smoke checks only that the schema's non-secret sentinel reaches a child process. The audit command explicitly excludes generated output, dependency, cache, and generated route-tree paths. The scan command checks staged files only and never opts into ignored output. The focused test runs redacted load, no-op run, and scan checks against sanitized present and missing import fixtures; it never reads the user-managed shared directory.
When an agent needs to run a secret-dependent command, inject values
through Varlock instead of reading .env:
varlock run --inject vars -- npx rafiki --prompt "..." --output output.png
varlock run --inject vars -- ./.venv/bin/python generate.py --prompt "..." --output output.pngnpm run doctorOr:
npx rafiki --doctornpx rafiki --prompt "A cinematic portrait of a radio host in a neon-lit studio" \
--output output.pngFor a public batch fixture:
npx rafiki examples/quickstart-image-prompts.md --dry-run --no-viewerFor the keynote visual workflow fixture:
npx rafiki examples/keynote-visual-workflow-prompt-pack.md --dry-run --no-viewerRun the deterministic local gate without registry access:
npm run verifyRun dependency vulnerability checks separately when network access is available:
npm run verify:securityThe security gate audits the root production graph, the frontend production and full dependency trees, and the reviewed Python CI lock. It fails on high-severity findings and never applies dependency fixes.
npx rafiki --prompt "A creative strategist sketching a systems map" --output hero.pngnpx rafiki /path/to/image-prompts.md --output-dir /path/to/output/projectnpx rafiki /path/to/image-prompts.md \
--style hopecode \
--output-dir /path/to/output/projectnpx rafiki --prompt "Minimal monochrome diagram" --no-style --output diagram.pngnpx rafiki \
--prompt "Keep the composition, modernize the visual language" \
--reference-image /path/to/reference.png \
--output output.pngnpx rafiki --render /path/to/card.html
npx rafiki --render-dir /path/to/html-assets/./.venv/bin/python generate.py --prompt "Your prompt" --output image.png
./.venv/bin/python generate.py --prompt-file image-prompts.md --output-dir ./images/Rafiki can be installed as a local MCP server so Codex, Claude Code, and other MCP clients can call it as tools instead of shelling out manually.
codex mcp add rafiki -- /path/to/rafiki/.venv/bin/python /path/to/rafiki/mcp_server.py
claude mcp add --scope user rafiki -- /path/to/rafiki/.venv/bin/python /path/to/rafiki/mcp_server.pyExposed tools include rafiki_generate, rafiki_batch,
rafiki_list_styles, rafiki_usage, rafiki_status, and rafiki_run for
the broader generate.py CLI surface.
Details: docs/MCP.md
Start the live portal shell:
mkdir -p output
python3 generate.py serveThe output directory must already exist. To use another existing archive root,
pass --output-dir /path/to/output.
By default it runs on http://localhost:7433/. Open
http://localhost:7433/library to use the current TypeScript image library or
http://localhost:7433/generate to build dry-run-first image generation runs.
The portal adds:
- persistent ratings stored on disk
- cross-project browsing and search
- viewer pages for image triage and metadata review
- run pages with missing-image placeholders and direct viewer links
- export, registry, health, and spend routes backed by local APIs
- generate workspace for single prompts, inline batches, Markdown prompt packs, model/style choices, and library/media references
The Generate route writes into output/<project>/run-* through the same
generation path as the CLI, so portal-generated runs show up in the normal
viewer and library flow. It defaults to dry-run; real provider calls require
explicit confirmation in the UI. Python remains the local filesystem, provider,
and API authority; the frontend is spawned behind the Python server. The legacy
rollback surfaces are available at /legacy-suite and /legacy-library.
The TypeScript portal is currently a repo-checkout capability. The public npm
package intentionally excludes frontend/, so npx rafiki serve from a package
install falls back to the legacy portal routes instead of building or starting
the React shell. See Frontend Shell for the package
boundary and release-policy checkpoint.
Useful commands:
python generate.py view <project>
python generate.py view <project> --all-runs
npx rafiki view <project> --all-runs
python generate.py library
python generate.py library --open
python generate.py archive-health --cleanup-report
npm run smoke:dry-runlibrary builds the full local archive: every run-* image under output/
and any configured extra-output roots, with approval state overlaid from
approved/index.json when available.
Rafiki batch runs parse numbered Markdown sections with blockquote prompts:
## 1. Hero Image
**For:** Article header
**Prompt:**
> A documentary-style portrait of a community organizer...
## 2. Quote Card
**For:** Social media
**Prompt:**
> Bold editorial typography over textured paper grain...Per-prompt overrides are supported:
## 1. Hero Banner
**Aspect Ratio:** 16:9
**Model:** gpt-image-2
**Style:** kk
**Quality:** high
**Prompt:**
> ...Rafiki supports both Gemini and OpenAI image models through the same CLI.
gemini-2.5-flash-image: fast iterationgemini-3-pro-image-preview: higher-end Gemini image generationgpt-image-2: strong general-purpose OpenAI image generationgpt-image-1dall-e-3
The CLI, portal, and MCP default is gemini-2.5-flash-image. Pass --model
to select another provider or model explicitly. Choose Gemini for fast local
iteration and Gemini Pro reference or high-resolution work. Choose OpenAI when
the prompt set was authored against OpenAI outputs, when you need OpenAI-only
model behavior, or when using the separate gpt-image-1 Streamlit workflow.
Details: docs/MODEL-POLICY.md
The GitHub repository is public, so any tracked prompt, asset, or doc should be treated as public. Keep private prompt libraries, private reference media, generated review outputs, and local-only paths outside the repo or untracked.
The public npm package stays narrower by design. It ships runtime code, docs,
styles, config examples, and only explicitly listed example prompt packs such
as examples/quickstart-image-prompts.md and
examples/keynote-visual-workflow-prompt-pack.md. It does not ship the
frontend/ workspace or frontend build artifacts until a maintainer approves a
package-policy change.
Details: docs/PROMPT-MEDIA-POLICY.md
Built-in styles are configured in styles/styles.yaml and can be composed
with +.
Examples (not exhaustive):
kkhopecodebcaifutureproof-mythicbcai-ecosystemupgradezinegnifemmeindigenomicscmvan
Useful commands:
npx rafiki --list-styles
npx rafiki --prompt "..." --style kk+bcaiIf you want the portal and library to include outputs that live outside this repo, copy the example file and create a local override:
cp config/extra-outputs.json.example config/extra-outputs.local.jsonExample:
{
"workshop-deck": "/absolute/path/to/another/project/output",
"campaign-assets": "/absolute/path/to/a/generated-images-directory"
}This file is intentionally gitignored.
For file:// viewing without the server, create symlinks into output/:
python generate.py link-projects- Provider keys belong in your shell environment or an untracked
.env .env.schemais the committed env contract for agents; usevarlock load --agent --show-allinstead of reading.env- agents must not run
env,printenv,varlock reveal, rawvarlock load, or any command that dumps the process environment - Agent-invoked commands that require resolved secrets should be wrapped
with
varlock run --inject vars -- python generate.py servebinds to127.0.0.1by default--publicrefuses to start unless bothPORTAL_USERNAMEandPORTAL_PASSWORDare set- Rafiki is a local-first tool, not a hosted multi-user platform
Read:
Useful commands:
npm test
npm run public:check
npm run pack:check
npm run docs:check
python3 -m pytest -qContribution guide: CONTRIBUTING.md
Start with the docs index for the full map.
Key references:
MIT. See LICENSE.