Kicon RFC 002 design generation pipeline
RFC-002 — Design Generation Pipeline
*uthor:*Koder Engineering *ate:*20260429 *tatus:*Accepted *odule:*productsdevkicon *elated:*kiconRFC001 (variant generation), hubRFC006 (Hub icon trigger), policies/sdk-first.kmd
Table of Contents
- Summary
- Problem Statement
- Goals
- Non-Goals
- Background
- Design
- 6.1 Subcommand Surface
- 6.2 Backend Abstraction
- 6.3 Procedural Backend
- 6.4 Imagegen Backend
- 6.5 Blender Backend
- 6.6 Vectorize Subcommand
- 6.7 Selection Workflow
- 6.8 Workdir Layout
- Scope of Change
- Execution Plan
- Dependencies
- Alternatives Considered
- References
1. Summary
Promote kicon from a buildtime *ariant generator*(one master SVG → N platformcorrect outputs, scope of RFC001) to a full *esign pipeline* master generation, candidate batch production across multiple backends, raster→vector conversion, interactive selection. The first real driver is the Koder Hub icon (hubRFC-006 §6.4); every Koder product downstream benefits from the same workflow when it needs a fresh icon.
2. Problem Statement
Today every Koder product that needs an icon goes through an ad-hoc external workflow: someone opens an image generation tool (Midjourney, DALL·E), iterates 20+ prompts, downloads PNGs, manually traces or hands them to a designer, drops the master into the module's directory, runs kicon generate. Three issues:
- *endor lock per icon.*Each round of generation is bespoke: different prompts, different services, different post-processing. Selection rationale is not reproducible.
- *o procedural option.*When a product just needs "a circular badge with the letter K and brand colors" there is no fast path — you still have to open a design tool. Procedural icons (badges, monograms, simple geometric forms) make up a meaningful slice of asks.
- *o 3D path inside the toolchain.*Photorealistic 3D icons (the Koder Jet path — memory
project_jet_icon_candidates) require Blender or a comparable tool, and there is no integration anywhere — every Koder product reinvents the rendering pipeline.
The Koder Hub rename (hubRFC006) needs 20 icon candidates following direction A (3D hub & spoke). It is the trigger to fix the pipeline once and for all instead of running the ad-hoc loop a sixteenth time.
3. Goals
- One CLI surface (
kicon design) covers every realistic generation path: procedural, imagemodel, 3Drendered. - Backend pluggability — a new generation source (e.g. Replicate, Flux, Midjourney) is added by implementing one Go interface.
- All image
model traffic flows throughcompatible facade), via theservices/ai/gateway/(existing OpenAIkoder_imagegen_kitSDK. No direct provider API calls inkiconor in any other consumer. Enforce SDK-first policy from one canonical place. - Reproducibility — every generated batch ships with a
manifest.jsonthat records prompt, parameters, backend, model, seed, timestamp. A future re-run with the same manifest must produce equivalent output. - Vectorization first-class — raster outputs from image models or 3D renders can be converted to SVG masters in the same tool, without leaving
kicon. - Selection workflow — pick from a candidate batch interactively (browser grid or terminal preview) and commit the chosen master into the module dir, ready for
kicon generate.
4. Non-Goals
- Replacing professional design tooling (Figma, Inkscape, Illustrator).
kicon designcovers the "I need a competent icon fast" case, not the "I need a brand identity system" case. - Training a custom Koder
style image model. The pipeline consumes offtheshelf models through the gateway; model finetuning is out of scope. - Hosting the gateway, the runtime, or any backend infrastructure.
kiconis a client; backends live where they always have (services/ai/gateway,services/ai/runtime). - Blender as a hard dependency. The Blender backend is opt-in; users without Blender installed see a clear "blender not found" message and can fall back to procedural or imagegen.
5. Background
kicon v0.2.x covers RFC-001: take one master SVG, validate it against specs/icons/products.kmd, emit platform variants (Android adaptive, iOS, macOS .icns, Windows .ico, Linux PNGs, web favicon, Hub catalog tile). It assumes the master already exists.
The gateway (services/ai/gateway/) already exposes POST /v1/images/generations (OpenAI-compatible) with two providers wired: OpenAI (DALL·E) and Stability (Stable Diffusion). Routing in cmd/gateway/main.go:routeImageRequest matches on model prefix. ImageProvider interface in internal/provider/provider.go is the extension point.
There is no existing Koder pattern for procedural icon templates and no existing Blender pipeline anywhere in the monorepo.
6. Design
6.1 Subcommand Surface
kicon design generate \
--backend procedural|imagegen|blender \
--template <name> | --prompt <text> | --scene <name> \
--params key=value,... \
--n 20 \
--out workdir/
kicon design pick workdir/ # opens browser grid; --no-browser for TTY
kicon design refine workdir/ --keep N,N,N --n 10
kicon design promote workdir/<id> --dest <module>/icon.svg
kicon vectorize <png> --backend vtracer|potrace --out <svg>kicon design generate produces a workdir of N candidates plus manifest.json. pick opens an interactive selector. refine regenerates a fresh batch biased toward the kept candidates (re-runs the same backend with parameter perturbations). promote installs the chosen candidate into a module's icon slot and runs kicon validate.
kicon vectorize is independent — it converts any PNG to SVG and is reused by both the imagegen and blender flows.
6.2 Backend Abstraction
package design
type Backend interface {
Name() string
Capabilities() Capabilities
Generate(ctx context.Context, spec Spec) (*Batch, error)
}
type Spec struct {
Template string // procedural template name OR blender scene name (mutually exclusive with Prompt)
Prompt string // imagegen
Params map[string]string // backend-specific parameters
N int
Seed *int
Size string // "1024x1024" etc.
Workdir string
}
type Capabilities struct {
AcceptsTemplate bool
AcceptsPrompt bool
AcceptsScene bool
OutputsSVG bool
OutputsPNG bool
Reproducible bool // same Spec → same Batch (with seed)
}
type Batch struct {
Candidates []Candidate
Manifest Manifest
}
type Candidate struct {
ID string // "01", "02", ...
Path string // relative to Workdir
Type string // "svg" | "png"
}Each backend is a Go package under internal/design/backend_<name>/ that registers itself via init() into a process-wide registry keyed by name.
6.3 Procedural Backend
internal/design/backend_procedural/. Templates are Go-templated SVG files in internal/design/templates/, one directory per template:
templates/
hub-and-spoke/
template.svg (Go text/template with parameter placeholders)
schema.json (parameter names, types, ranges, defaults)
samples.yaml (curated parameter combinations, used as the seed batch)A run with --n 20 either picks 20 entries from samples.yaml (if present and ≥N) or generates 20 random parameter combinations within schema.json ranges. --params overrides specific keys.
First template ships: *hubandspoke`* Parameters:
spoke_count(4..6)spoke_endpoint_shape(cube | sphere | prism, varied per spoke)core_color,spoke_color,endpoint_palettegradient_intensity(0.0..1.0, simulates 3D depth via radial gradients)rotation_offset_deg
Output is SVG. OutputsSVG=true, Reproducible=true (deterministic given seed).
Future templates that fit procedural well: badge (circular emblem with letter), monogram (letter pair in geometric layout), token (gem/coin shape), grid (logo as cell layout).
6.4 Imagegen Backend
internal/design/backend_imagegen/. Calls services/ai/gateway/v1/images/generations via the *koderimagegenkit`*SDK (created as part of this RFC, see §7) — never the provider APIs directly.
Per-call parameters mapped from Spec:
Prompt→prompt--params model=dall-e-3→model--params size=1024x1024→sizeN→n(requests N images in one call when supported, else loops)Seed→seed(when the underlying provider supports it; SDXL does, DALL·E does not)--params response_format=b64_json→ returns inline base64 (preferred over signed URLs to avoid the URL-expiry race)
Output is PNG. OutputsPNG=true, Reproducible= whatever the underlying provider claims via the SDK.
Models the gateway will route correctly (already in K9 inventory):
dall-e-3,dall-e-2→ OpenAI providerstable-diffusion-xl-1024-v1-0,stable-diffusion-3-medium,flux.1-*→ Stability or runtime providerimagen-3→ Google provider (added by K9)koder/sdxl-local,koder/flux-local→ koder_runtime provider (added by K9)
6.5 Blender Backend
internal/design/backend_blender/. Shells out to blender --background --python <script> -- <args>. Scenes live in internal/design/scenes/<name>.blend paired with internal/design/scenes/<name>.py that exposes parameters via argparse and writes one render per invocation.
First scene ships: *hubandspoke.blend** with parameters mirroring the procedural template (spoke_count, materials, lighting profile). For N candidates, kicon` invokes Blender N times with parameter variations and collects the rendered PNGs.
Detection: blender --version at backend init; if absent, the backend registers itself but Generate returns a clear "blender not installed" error pointing at install instructions.
Output is PNG. OutputsPNG=true, Reproducible=true (Cycles with fixed seed is deterministic given the same .blend + script + args).
6.6 Vectorize Subcommand
cmd/kicon/vectorize.go + internal/vectorize/. Two backends:
- *tracer*(preferred) — modern, color-aware, produces clean paths for illustrations. Install:
cargo install vtraceror use the prebuilt binary. Tunables: color count, filter speckle, path simplify. - *otrace*— fallback, monochrome only, ubiquitous on Linux distros.
kicon vectorize foo.png --backend vtracer --colors 8 --simplify 4 --out foo.svgAlways runs the resulting SVG through kicon validate and reports any spec violations.
6.7 Selection Workflow
kicon design pick <workdir> opens a local HTTP server on 127.0.0.1:7654 and a browser window with a grid of candidates. Each candidate has Approve / Reject / Star buttons; the user can also edit the prompt or template parameters and request a refine round inline. State persists in <workdir>/picks.json.
TTY fallback (--no-browser): list candidates numerically, render previews via chafa (256-color terminal images) when available, otherwise show paths and let the user open them externally.
kicon design promote <workdir>/<id> --dest <module>/icon.svg:
- If candidate is SVG → copy directly, then
kicon validate. - If candidate is PNG → run
kicon vectorizewith sensible defaults, thenkicon validate. User can rerunvectorization is unsatisfactory.vectorizemanually with custom params if the auto
6.8 Workdir Layout
workdir/
manifest.json # backend, model, prompt/template, params, seed, timestamp, kicon version
candidate-01.svg|png
candidate-02.svg|png
...
picks.json # per-candidate: status (pending|approved|rejected|starred), notes
refines/
01/ # nested workdir, same layout, parent_picks pointer in manifestManifest schema versioned (schema_version: 1). Future kicon design replay <manifest> reproduces a batch from a manifest alone.
7. Scope of Change
Codified into 12 tasks (K1..K12) in the project task list, mapped here:
| # | Item | Module |
|---|---|---|
| K1 | Mapping (done) | — |
| K2 | This RFC | products/dev/kicon/docs/rfcs/ |
| K3 | Tickets in koder-stack + kicon backlogs | projects/koder-stack/backlog/, products/dev/kicon/backlog/ |
| K4 | design subcommand skeleton + procedural backend + hub-and-spoke template |
products/dev/kicon/{cmd,internal/design}/ |
| K5 | imagegen backend (direct gateway HTTP first) | products/dev/kicon/internal/design/backend_imagegen/ |
| K6 | vectorize subcommand |
products/dev/kicon/{cmd,internal/vectorize}/ |
| K7 | Blender backend + first scene | products/dev/kicon/internal/design/backend_blender/ + scenes/ |
| K8 | pick / refine / promote subcommands |
products/dev/kicon/cmd/ + internal/design/picker/ |
| K9 | Gateway image-gen backends (Imagen, koder_runtime) | services/ai/gateway/internal/provider/ |
| K10 | koder_imagegen_kit SDK (Go + Dart) |
engines/sdk/imagegen/ (Dart) + engines/sdk/go-imagegen/ (Go) |
| K11 | Migrate kicon's imagegen backend to use the SDK | products/dev/kicon/internal/design/backend_imagegen/ |
| K12 | E2E validation: generate Hub icon (resolves backlog #036) | — |
8. Execution Plan
Sequenced for shippability — every checkpoint produces something usable on its own.
| Stage | Tickets | Deliverable | Status |
|---|---|---|---|
| 1 | K1, K2, K3 | Plan + RFC + tickets in backlog | F1 of Hub work proceeds in parallel |
| 2 | K4 | kicon design generate --backend procedural --template hub-and-spoke --n 20 produces 20 SVG candidates in workdir |
First usable slice |
| 3 | K5 | Same command works with --backend imagegen --prompt "..." (direct gateway HTTP) |
Image-model path live |
| 4 | K6 | kicon vectorize available; PNG candidates from K5 can be promoted to SVG masters |
Full PNG → SVG → variants chain |
| 5 | K7 | Blender backend works for any user with Blender installed; first scene shipped | 3D path live |
| 6 | K8 | kicon design pick opens browser grid, promote writes the chosen master |
UX complete |
| 7 | K9 | Gateway routes Imagen + koder_runtime alongside OpenAI/Stability | More models reachable |
| 8 | K10 | SDK published; first consumer is kicon | SDK-first compliance |
| 9 | K11 | kicon's imagegen backend refactored to consume the SDK | Direct HTTP removed |
| 10 | K12 | Hub icon batch generated, picked, promoted | Backlog #036 resolved; Hub |
Stages 2–6 deliver kicon v2 standalone. Stages 7–9 deliver the meta layer per policies/sdk-first.kmd. Stage 10 closes the loop with the original trigger.
9. Dependencies
services/ai/gateway/already exposes the image generation endpoint (K1 confirmed).vtracer(Rust) and/orpotrace(C) for K6. Both are offtheshelf binaries with permissive licenses.- Blender 3.x+ for K7 (optional — backend gracefully degrades when absent).
chafafor K8 TTY fallback (optional).- Hub
RFC006 (the trigger) does not block kicon work; the Hub rename can proceed with placeholder icon and have the real icon slotted in via K12 before F5 of the Hub plan.
10. Alternatives Considered
- *dd image generation logic directly to each consumer (kicon, hub landing page generator, etc.)*— rejected: violates
policies/sdk-first.kmd, fragments backend choice, makes A/B-ing models impossible. - *ake
services/ai/image-gen/a separate service*— considered. Rejected because the gateway already owns the OpenAIcompatible facade and adding a parallel surface duplicates auth, audit, ratelimit, billing, cache. Easier to extend the gateway than fork it. - *se Midjourney as the canonical backend*— rejected: no first-party API, requires Discord proxy (against ToS for many use cases), poor reproducibility.
- *kip procedural backend and rely solely on image models*— rejected: procedural is faster, deterministic, free, and covers a real slice of asks (badges, monograms). Loss of vendor independence too high otherwise.
- *kip Blender backend and rely on raster→vector for 3D*— rejected: vectorization of photorealistic 3D loses too much detail; for 3D
assource workflows, Blender is the right tool. Optional dependency keeps the cost low. - *uild a custom GUI app for selection instead of HTTP+browser*— rejected: browser is universal, zero
install on the user side, easy to embed images, fits the Koder Stack's webfirst ergonomics.
11. References
kicon-RFC-001-icon-generation.md— variant generation (the "after master exists" half)hub-RFC-006-unification-and-rename.md§6.4 — the Hub icon triggerspecs/icons/products.kmd— icon contract (3D, forma=conceito, sem fundo)specs/icons/generation-targets.kmd— per-platform variant rules consumed bykicon generateservices/ai/gateway/api/openapi.yaml— image-gen endpoint contractservices/ai/gateway/internal/provider/provider.go—ImageProviderinterfacepolicies/sdk-first.kmd— enforcement rationale for §6.4 SDK choice- Memory
project_jet_icon_candidates— Jet went PNG-photorealistic; informs the K7 Blender path - Memory
project_flow_icon_selection— Flow batch selection workflow that K8 generalizes