{"id":"eb2342fa-ef49-412b-9203-01e8efbd8de9","entityType":"agent","slug":"clawhub-tmchow-illo","name":"illo","canonicalUrl":"https://www.xpersona.co/agent/clawhub-tmchow-illo","canonicalPath":"/agent/clawhub-tmchow-illo","generatedAt":"2026-10-09T14:58:01.791Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T09:56:01.893Z","emptyReason":null},"description":"Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the structure itself is the point, or a transparent character cutout (pose-only compositing asset, no scene or text) — in one of seventeen bundled looks (sixteen print, plus a photoreal toy-brick set). Also handles \"surprise me\" / \"random\" (optionally scoped to a focus or character): rolls provenance, builds three saying candidates, picks via interactive choice or auto-pick-best (`--autopick`), and renders one image. Triggers only when the skill is directly invoked or \"illo\" is requested; never on generic illustrate / draw / make-an-image requests. Skill: illo Owner: tmchow Summary: Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the structure itself is the point, or a transparent character cutout (pose-only compositing asset, no scene or text) — in one of seventeen bundled looks (sixteen print, p","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 3.1K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17f9h004hads3st3t2xbtmhr585rjvr:illo","sourceUrl":"https://clawhub.ai/tmchow/illo","homepage":"https://clawhub.ai/tmchow/skills/illo","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/tmchow/illo","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/tmchow/skills/illo","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":70,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (lab"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T09:56:01.893Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T09:56:01.893Z","emptyReason":null},"stars":null,"forks":null,"downloads":3074,"packageName":null,"latestVersion":"0.37.0","tractionLabel":"3.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T09:56:01.865Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T09:56:01.893Z","lastCrawledAt":"2026-10-09T09:56:01.865Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T09:56:01.865Z","lastVerifiedAt":null,"highlights":[{"version":"0.37.0","createdAt":"2026-09-21T20:20:53.020Z","changelog":"## [0.37.0](https://github.com/tmchow/illo-skill/compare/v0.36.0...v0.37.0) (2026-09-21) ### Features * add Muse native image transport ([#76](https://github.com/tmchow/illo-skill/issues/76)) ([e26efee](https://github.com/tmchow/illo-skill/commit/e26efee664965b1408bc5a4bdcb5b08cdc0e97dd))","fileCount":38,"zipByteSize":195212},{"version":"0.36.0","createdAt":"2026-09-17T17:48:49.040Z","changelog":"## [0.36.0](https://github.com/tmchow/illo-skill/compare/v0.35.0...v0.36.0) (2026-09-17) ### Features * support GPT Image 2.5 Flare through OpenRouter ([#75](https://github.com/tmchow/illo-skill/issues/75)) ([0defa0b](https://github.com/tmchow/illo-skill/commit/0defa0b842125c63e51f1f2fb09e8f76319bf8fb)) ### Bug Fixes * make the repo README a product poster ([#71](https://github.com/tmchow/illo-skill/issues/71)) ([74c05dd](https://github.com/tmchow/illo-skill/commit/74c05ddce8c581a18e6095140f6b41b14a52bef9)) * point Grok Bot install at the shareable template ([#73](https://github.com/tmchow/illo-skill/issues/73)) ([6623c82](https://github.com/tmchow/illo-skill/commit/6623c82d40c6b3e0a4d44333288e4b436b8047c2))","fileCount":38,"zipByteSize":192070},{"version":"0.35.0","createdAt":"2026-08-23T22:04:33.452Z","changelog":"## [0.35.0](https://github.com/tmchow/illo-skill/compare/v0.34.4...v0.35.0) (2026-08-23) ### Features * add labeled-stages explainer type, pack-solve, and arrow notes ([#69](https://github.com/tmchow/illo-skill/issues/69)) ([a081033](https://github.com/tmchow/illo-skill/commit/a0810330f4148b09b42d599247a14d004a1c58cf))","fileCount":38,"zipByteSize":190281},{"version":"0.34.4","createdAt":"2026-08-22T04:13:58.081Z","changelog":"## [0.34.4](https://github.com/tmchow/illo-skill/compare/v0.34.3...v0.34.4) (2026-08-22) ### Bug Fixes * use Codex native alpha for cutouts ([#67](https://github.com/tmchow/illo-skill/issues/67)) ([33636a4](https://github.com/tmchow/illo-skill/commit/33636a407caff18736107e608f7cfb042eb3e17a))","fileCount":37,"zipByteSize":178114},{"version":"0.34.3","createdAt":"2026-08-17T19:52:07.967Z","changelog":"## [0.34.3](https://github.com/tmchow/illo-skill/compare/v0.34.2...v0.34.3) (2026-08-17) ### Bug Fixes * keep successful chroma cutouts transparent ([#65](https://github.com/tmchow/illo-skill/issues/65)) ([194e412](https://github.com/tmchow/illo-skill/commit/194e412fa9f8b48990c0bf8a0380d6fc5d23acd1))","fileCount":37,"zipByteSize":176580},{"version":"0.34.2","createdAt":"2026-08-16T17:38:59.812Z","changelog":"## [0.34.2](https://github.com/tmchow/illo-skill/compare/v0.34.1...v0.34.2) (2026-08-16) ### Bug Fixes * **illo:** surprise-me keepers, earned register, character refresh ([#63](https://github.com/tmchow/illo-skill/issues/63)) ([4d30579](https://github.com/tmchow/illo-skill/commit/4d30579515f37db0f854d0a9f53c0ba8c66969f1))","fileCount":37,"zipByteSize":173419},{"version":"0.34.1","createdAt":"2026-08-16T09:01:48.505Z","changelog":"## [0.34.1](https://github.com/tmchow/illo-skill/compare/v0.34.0...v0.34.1) (2026-08-16) ### Bug Fixes * don't narrate illo workflow ([#61](https://github.com/tmchow/illo-skill/issues/61)) ([6dc310d](https://github.com/tmchow/illo-skill/commit/6dc310d4d075c079d0dfcd559c99eeaed7b368ad))","fileCount":37,"zipByteSize":172448},{"version":"0.34.0","createdAt":"2026-08-16T08:50:14.692Z","changelog":"## [0.34.0](https://github.com/tmchow/illo-skill/compare/v0.33.0...v0.34.0) (2026-08-16) ### Features * document Grok Bot native image transport ([#58](https://github.com/tmchow/illo-skill/issues/58)) ([6d98f28](https://github.com/tmchow/illo-skill/commit/6d98f28cf9672fa354228e2fd2dc7d337f826912)) ### Bug Fixes * reject moralizing turns in surprise-me sayings ([#60](https://github.com/tmchow/illo-skill/issues/60)) ([f3f6aa8](https://github.com/tmchow/illo-skill/commit/f3f6aa80b113e9892943a2c615257237143b8324))","fileCount":37,"zipByteSize":172381}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17f9h004hads3st3t2xbtmhr585rjvr:illo","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T14:58:01.782Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-tmchow-illo/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T09:56:01.893Z","emptyReason":null},"readme":"Skill: illo\n\nOwner: tmchow\n\nSummary: Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the structure itself is the point, or a transparent character cutout (pose-only compositing asset, no scene or text) — in one of seventeen bundled looks (sixteen print, plus a photoreal toy-brick set). Also handles \"surprise me\" / \"random\" (optionally scoped to a focus or character): rolls provenance, builds three saying candidates, picks via interactive choice or auto-pick-best (`--autopick`), and renders one image. Triggers only when the skill is directly invoked or \"illo\" is requested; never on generic illustrate / draw / make-an-image requests.\n\nTags: latest:0.37.0\n\nVersion history:\n\nv0.37.0 | 2026-09-21T20:20:53.020Z | user\n\n## [0.37.0](https://github.com/tmchow/illo-skill/compare/v0.36.0...v0.37.0) (2026-09-21)\n\n\n### Features\n\n* add Muse native image transport ([#76](https://github.com/tmchow/illo-skill/issues/76)) ([e26efee](https://github.com/tmchow/illo-skill/commit/e26efee664965b1408bc5a4bdcb5b08cdc0e97dd))\n\nv0.36.0 | 2026-09-17T17:48:49.040Z | user\n\n## [0.36.0](https://github.com/tmchow/illo-skill/compare/v0.35.0...v0.36.0) (2026-09-17)\n\n\n### Features\n\n* support GPT Image 2.5 Flare through OpenRouter ([#75](https://github.com/tmchow/illo-skill/issues/75)) ([0defa0b](https://github.com/tmchow/illo-skill/commit/0defa0b842125c63e51f1f2fb09e8f76319bf8fb))\n\n\n### Bug Fixes\n\n* make the repo README a product poster ([#71](https://github.com/tmchow/illo-skill/issues/71)) ([74c05dd](https://github.com/tmchow/illo-skill/commit/74c05ddce8c581a18e6095140f6b41b14a52bef9))\n* point Grok Bot install at the shareable template ([#73](https://github.com/tmchow/illo-skill/issues/73)) ([6623c82](https://github.com/tmchow/illo-skill/commit/6623c82d40c6b3e0a4d44333288e4b436b8047c2))\n\nv0.35.0 | 2026-08-23T22:04:33.452Z | user\n\n## [0.35.0](https://github.com/tmchow/illo-skill/compare/v0.34.4...v0.35.0) (2026-08-23)\n\n\n### Features\n\n* add labeled-stages explainer type, pack-solve, and arrow notes ([#69](https://github.com/tmchow/illo-skill/issues/69)) ([a081033](https://github.com/tmchow/illo-skill/commit/a0810330f4148b09b42d599247a14d004a1c58cf))\n\nv0.34.4 | 2026-08-22T04:13:58.081Z | user\n\n## [0.34.4](https://github.com/tmchow/illo-skill/compare/v0.34.3...v0.34.4) (2026-08-22)\n\n\n### Bug Fixes\n\n* use Codex native alpha for cutouts ([#67](https://github.com/tmchow/illo-skill/issues/67)) ([33636a4](https://github.com/tmchow/illo-skill/commit/33636a407caff18736107e608f7cfb042eb3e17a))\n\nv0.34.3 | 2026-08-17T19:52:07.967Z | user\n\n## [0.34.3](https://github.com/tmchow/illo-skill/compare/v0.34.2...v0.34.3) (2026-08-17)\n\n\n### Bug Fixes\n\n* keep successful chroma cutouts transparent ([#65](https://github.com/tmchow/illo-skill/issues/65)) ([194e412](https://github.com/tmchow/illo-skill/commit/194e412fa9f8b48990c0bf8a0380d6fc5d23acd1))\n\nv0.34.2 | 2026-08-16T17:38:59.812Z | user\n\n## [0.34.2](https://github.com/tmchow/illo-skill/compare/v0.34.1...v0.34.2) (2026-08-16)\n\n\n### Bug Fixes\n\n* **illo:** surprise-me keepers, earned register, character refresh ([#63](https://github.com/tmchow/illo-skill/issues/63)) ([4d30579](https://github.com/tmchow/illo-skill/commit/4d30579515f37db0f854d0a9f53c0ba8c66969f1))\n\nv0.34.1 | 2026-08-16T09:01:48.505Z | user\n\n## [0.34.1](https://github.com/tmchow/illo-skill/compare/v0.34.0...v0.34.1) (2026-08-16)\n\n\n### Bug Fixes\n\n* don't narrate illo workflow ([#61](https://github.com/tmchow/illo-skill/issues/61)) ([6dc310d](https://github.com/tmchow/illo-skill/commit/6dc310d4d075c079d0dfcd559c99eeaed7b368ad))\n\nv0.34.0 | 2026-08-16T08:50:14.692Z | user\n\n## [0.34.0](https://github.com/tmchow/illo-skill/compare/v0.33.0...v0.34.0) (2026-08-16)\n\n\n### Features\n\n* document Grok Bot native image transport ([#58](https://github.com/tmchow/illo-skill/issues/58)) ([6d98f28](https://github.com/tmchow/illo-skill/commit/6d98f28cf9672fa354228e2fd2dc7d337f826912))\n\n\n### Bug Fixes\n\n* reject moralizing turns in surprise-me sayings ([#60](https://github.com/tmchow/illo-skill/issues/60)) ([f3f6aa8](https://github.com/tmchow/illo-skill/commit/f3f6aa80b113e9892943a2c615257237143b8324))\n\nv0.33.0 | 2026-08-12T15:38:21.465Z | user\n\n## [0.33.0](https://github.com/tmchow/illo-skill/compare/v0.32.1...v0.33.0) (2026-08-01)\n\n\n### Features\n\n* **illo:** add interaction models and an anatomy-action feasibility gate ([#56](https://github.com/tmchow/illo-skill/issues/56)) ([2ed420a](https://github.com/tmchow/illo-skill/commit/2ed420a3094179078daf48e27ffb743b42c0895b))\n\nv0.32.1 | 2026-07-26T08:22:48.096Z | user\n\n## [0.32.1](https://github.com/tmchow/illo-skill/compare/v0.32.0...v0.32.1) (2026-07-26)\n\n\n### Bug Fixes\n\n* **illo:** re-roll provenance and topic on surprise refresh ([#54](https://github.com/tmchow/illo-skill/issues/54)) ([3934b3a](https://github.com/tmchow/illo-skill/commit/3934b3a1c14717668d1b775f4a00f57b735f5884))\n\nv0.32.0 | 2026-07-26T07:25:53.720Z | user\n\n## [0.32.0](https://github.com/tmchow/illo-skill/compare/v0.31.6...v0.32.0) (2026-07-26)\n\n\n### Features\n\n* **illo:** roll surprise provenance and pick among three sayings ([#52](https://github.com/tmchow/illo-skill/issues/52)) ([ffab6b2](https://github.com/tmchow/illo-skill/commit/ffab6b233c2dd03022bdebbd9f569e47b09c5cef))\n\nv0.31.6 | 2026-07-26T06:00:12.293Z | user\n\n## [0.31.6](https://github.com/tmchow/illo-skill/compare/v0.31.5...v0.31.6) (2026-07-26)\n\n\n### Features\n\n* add bundled SNES illustration look ([a10c62e](https://github.com/tmchow/illo-skill/commit/a10c62e069d6b552a3f4aced429529f5fd0fb607))\n\n\n### Bug Fixes\n\n* validate release commit metadata ([0d78b0b](https://github.com/tmchow/illo-skill/commit/0d78b0b4d67d7ac6fd1fbdecf328dfbdb54f8048))\n\nv0.31.5 | 2026-07-14T05:32:00.496Z | user\n\n## [0.31.5](https://github.com/tmchow/illo-skill/compare/v0.31.4...v0.31.5) (2026-07-14)\n\n\n### Bug Fixes\n\n* **illo:** scope Codex artifacts to exec thread ([7e05fcb](https://github.com/tmchow/illo-skill/commit/7e05fcbced6d1dbd3c24f5d408162dceaadf4ceb))\n\nv0.31.4 | 2026-07-14T05:09:33.885Z | user\n\n## [0.31.4](https://github.com/tmchow/illo-skill/compare/v0.31.3...v0.31.4) (2026-07-14)\n\n\n### Bug Fixes\n\n* **illo:** exclude prior count-batch artifacts from freshness fallback ([acd3920](https://github.com/tmchow/illo-skill/commit/acd39201602799f688e42424146a138fc83c93c0))\n\nv0.31.3 | 2026-07-14T04:07:07.882Z | user\n\n## [0.31.3](https://github.com/tmchow/illo-skill/compare/v0.31.2...v0.31.3) (2026-07-14)\n\n\n### Bug Fixes\n\n* **illo:** trust artifacts and gate paid fallback ([30b05ea](https://github.com/tmchow/illo-skill/commit/30b05ea0ae23554112f8ee7febbac1872776bb34))\n\nv0.31.2 | 2026-07-13T17:30:01.460Z | user\n\n## [0.31.2](https://github.com/tmchow/illo-skill/compare/v0.31.1...v0.31.2) (2026-07-13)\n\n\n### Bug Fixes\n\n* **codex:** sharpen plugin starter prompts ([74baf9b](https://github.com/tmchow/illo-skill/commit/74baf9b2860fe1a833711623d2b8209f6de13155))\n* **codex:** sharpen plugin starter prompts ([4104465](https://github.com/tmchow/illo-skill/commit/4104465075f8f5a833f6994df1f76614d42367f7))\n\nv0.31.1 | 2026-07-13T17:18:53.735Z | user\n\n## [0.31.1](https://github.com/tmchow/illo-skill/compare/v0.31.0...v0.31.1) (2026-07-13)\n\n\n### Bug Fixes\n\n* **codex:** enrich plugin install metadata ([d6a706a](https://github.com/tmchow/illo-skill/commit/d6a706aee4945daf109b178d938b6aff1d05bc22))\n* **codex:** enrich plugin metadata ([7bf6421](https://github.com/tmchow/illo-skill/commit/7bf64211a3ad547e44897d784cf3f02da5e8c728))\n\nv0.31.0 | 2026-07-13T01:48:04.696Z | user\n\n## [0.31.0](https://github.com/tmchow/illo-skill/compare/v0.30.0...v0.31.0) (2026-07-13)\n\n\n### Features\n\n* **illo:** add surprise-me / random headless generation mode ([8f47fd7](https://github.com/tmchow/illo-skill/commit/8f47fd7bd9bf854ace8f0e373b35aba5e21effb8))\n* **illo:** add surprise-me / random headless generation mode ([855e265](https://github.com/tmchow/illo-skill/commit/855e265767670623d996d0678ddfac1fa4b09266))\n\n\n### Bug Fixes\n\n* **skill:** make $SKILL_DIR engine blocks flatten-safe ([bf9d092](https://github.com/tmchow/illo-skill/commit/bf9d092809cfca759e34a6b8a165664c7fc5b9d3))\n* **skill:** make $SKILL_DIR engine blocks flatten-safe ([c4f3bfb](https://github.com/tmchow/illo-skill/commit/c4f3bfb001e1b001027f9018f81f1a1e85f37664))\n\nv0.30.0 | 2026-07-11T08:12:37.913Z | user\n\n## [0.30.0](https://github.com/tmchow/illo-skill/compare/v0.29.0...v0.30.0) (2026-07-11)\n\n\n### Features\n\n* **grok:** add Grok image backend ([2060546](https://github.com/tmchow/illo-skill/commit/2060546f37daad1bc789e97ed41659b66cf77dd2))\n\n\n### Bug Fixes\n\n* **codex:** detect image backend by image_generation alone ([943ad29](https://github.com/tmchow/illo-skill/commit/943ad291dfd7db7c3fb766595f07b244ba72937f))\n* **codex:** detect image backend by image_generation alone ([e3ef349](https://github.com/tmchow/illo-skill/commit/e3ef349a96c8ebe5e01808c35f64314e9ccf522c))\n* **grok:** apply default-character ref on the OpenRouter fallback path ([#30](https://github.com/tmchow/illo-skill/issues/30)) ([63b4c3e](https://github.com/tmchow/illo-skill/commit/63b4c3e98d235dc75ddf45e76451f45fa9a0760b))\n* **grok:** sandbox the agent, fix cutout fallback model, refresh backend docs ([57f9407](https://github.com/tmchow/illo-skill/commit/57f9407b6705ceb9375a6627a99c7528eb511f26))\n\nv0.29.0 | 2026-07-09T17:02:23.202Z | user\n\n## [0.29.0](https://github.com/tmchow/illo-skill/compare/v0.28.2...v0.29.0) (2026-07-09)\n\n\n### Features\n\n* **grok:** add native Grok plugin and marketplace lane ([c9543fe](https://github.com/tmchow/illo-skill/commit/c9543fe1abb31b1ceef212aa16d6498f1bc8f11b))\n* **grok:** add native Grok plugin and marketplace manifests ([7c5e0cd](https://github.com/tmchow/illo-skill/commit/7c5e0cd0e7a0118b59142fcd558b8f43a0e105ee))\n* **grok:** wire Grok manifests into version lockstep ([91ba84f](https://github.com/tmchow/illo-skill/commit/91ba84fad0014fa2b9a4e6c737dbed40b6aa446a))\n\n\n### Bug Fixes\n\n* distinguish X Article banner guidance ([23dfd1e](https://github.com/tmchow/illo-skill/commit/23dfd1ee678074aef7ad0e73287d141af0071424))\n* resolve codex binary path for subprocess on Windows ([25bece9](https://github.com/tmchow/illo-skill/commit/25bece94297df9615ee3eebfc7fa1e019a0bfe20))\n\nv0.28.2 | 2026-06-30T06:56:33.266Z | user\n\nPublish illo 0.28.2 from f47c394a2e052a2c4c0e3286ee0d5e1e7ae097bb\n\nv0.28.1 | 2026-06-28T01:59:36.856Z | user\n\nPublish illo 0.28.1 from 25b3cda6e4307d1df7356127c76dbd11052ab529\n\nv0.28.0 | 2026-06-23T21:23:28.764Z | user\n\nPublish illo 0.28.0 from 8d65ef13e4515a193f3182c155c6021b24f782a4\n\nv0.27.0 | 2026-06-23T18:26:42.543Z | user\n\nPublish illo 0.27.0 from b79c6cb6bfcc2d3691f548209bb2bba31276a553\n\nv0.26.0 | 2026-06-21T22:32:54.421Z | user\n\nPublish illo 0.26.0 from 346f69cd87d47f0f8c7f01aa4cac81f423c3bc80\n\nv0.25.0 | 2026-06-19T23:20:51.314Z | user\n\nPublish illo 0.25.0 from 9a9a55f8d35e1f3337daff28a2cb2f8d543ec641\n\nv0.24.0 | 2026-06-19T17:26:50.692Z | user\n\nPublish illo 0.24.0 from 2f2ba733290433860816bf3e00cf6e795b478fb0\n\nv0.23.5 | 2026-06-19T00:45:16.335Z | user\n\nPublish illo 0.23.5 from 2a2450f37568bca98986cfe52e9fd297044c3b85\n\nv0.23.4 | 2026-06-17T16:46:43.032Z | user\n\nPublish illo 0.23.4 from 99ad39f9743a184537e90b00e4226edf83c72923\n\nv0.23.3 | 2026-06-17T14:57:13.725Z | user\n\nPublish illo 0.23.3 from 66f52b1c4381776ee274ebb9bb7f114bc712016b\n\nv0.23.2 | 2026-06-15T23:18:42.664Z | user\n\nPublish illo 0.23.2 from a22936db059a3342aa856ca0e8ffa5097594bea8\n\nv0.23.1 | 2026-06-15T23:13:55.625Z | user\n\nPublish illo 0.23.1 from 4dad47e6d47e269714e7d4a5d9127143f070bdf5\n\nv0.23.0 | 2026-06-15T06:58:09.939Z | user\n\nPublish illo 0.23.0 from 5f13471eb8683f528d4dca8173f87a78b7eb829a\n\nv0.22.2 | 2026-06-15T06:02:52.655Z | user\n\nPublish illo 0.22.2 from 21ed05f782cb141b028f56022b8b20580112a613\n\nv0.22.1 | 2026-06-13T18:11:59.954Z | user\n\nPublish illo 0.22.1 from 92ec96cc60b8ec837d360636d22f8d5004771232\n\nv0.22.0 | 2026-06-13T00:53:49.145Z | user\n\nPublish illo 0.22.0 from ca7a3d59d85f09e53b78a4f62485bfe4a32f85da\n\nv0.21.0 | 2026-06-12T17:31:41.528Z | user\n\nPublish illo 0.21.0 from 1e4520938a276891186760de3337653c2ecf7248\n\nv0.20.1 | 2026-06-12T16:43:30.267Z | user\n\nPublish illo 0.20.1 from ba8f1569f05916bb5cfa5f645919410eb3607104\n\nv0.20.0 | 2026-06-12T16:14:36.175Z | user\n\nPublish illo 0.20.0 from 37d85e653e5fafb69d3878b7f79b6da841650679\n\nv0.19.0 | 2026-06-12T15:27:31.491Z | user\n\nPublish illo 0.19.0 from 81838d116d012eb3b6f1dd3cdb02e0c9ea91e209\n\nArchive index:\n\nArchive v0.37.0: 38 files, 195212 bytes\n\nFiles: assets/checksums.txt (416b), NOTICE (703b), README.md (19115b), references/article-set-character-reroute.md (3926b), references/backends.md (20273b), references/character-builder.md (13383b), references/character.md (11398b), references/composition.md (34982b), references/cutout.md (16227b), references/models.md (6686b), references/pack-sharing.md (6682b), references/palettes.md (5453b), references/prompt-recipe.md (17802b), references/quality-bar.md (18521b), references/styles/bloom.md (5621b), references/styles/blueprint.md (2987b), references/styles/bricks.md (6652b), references/styles/chalk.md (2893b), references/styles/clay.md (3723b), references/styles/diorama.md (5521b), references/styles/enamel.md (3999b), references/styles/felt.md (5526b), references/styles/fizz.md (5299b), references/styles/gouache.md (3150b), references/styles/manila.md (3316b), references/styles/phosphor.md (3117b), references/styles/pixel.md (2919b), references/styles/sketchbook.md (6976b), references/styles/snes.md (8605b), references/styles/woodcut.md (2634b), references/surprise.md (28727b), references/visual-style.md (3482b), scripts/diagram_route.py (25195b), scripts/illo.py (107599b), scripts/repair-hermes-assets.sh (2137b), skill-card.md (2794b), SKILL.md (52904b), _meta.json (124b)\n\nFile v0.37.0:SKILL.md\n\n---\nname: illo\ndescription: >-\n  Creates original editorial illustrations where a recurring mascot\n  character performs the idea — one caught scene by default, a hand-built\n  explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the\n  structure itself is the point, or a transparent character cutout\n  (pose-only compositing asset, no scene or text) — in one of seventeen bundled\n  looks (sixteen print, plus a photoreal toy-brick set). Also handles\n  \"surprise me\" / \"random\" (optionally scoped to a focus or character): rolls\n  provenance, builds three saying candidates, picks via interactive choice or\n  auto-pick-best (`--autopick`), and renders one image. Triggers only when\n  the skill is directly invoked or \"illo\" is requested; never on generic\n  illustrate / draw / make-an-image requests.\n# x-release-please-start-version\nversion: 0.37.0\n# x-release-please-end\nargument-hint: \"[idea or article URL] | build a character | install <character> | surprise me [focus] [--autopick] [using character]\"\nauthor: Trevin Chow\nlicense: MIT\nmetadata:\n  hermes:\n    tags: [illustration, riso, image-generation, editorial, mascot, codex, grok, openrouter, muse]\n    category: creative\n    requires_toolsets: [terminal]\n  openclaw:\n    emoji: \"🎨\"\n    homepage: https://illo-skill.com\n    os: [macos, linux]\n    requires:\n      bins: [python3]\n---\n\n# Illo\n\nMake original, distinctive editorial illustrations for written content. One\nimage explains one idea: a key judgment, a flow, a before/after, a trap, a\nloop. A **recurring mascot** is the one performing the idea in every scene —\nthe subject, never decoration. When one idea advances through stages, it can\nbe a **mini-comic**: 2–4 panels inside a single image. And when the idea is\nitself a traceable structure — a pipeline, labeled stages, a fan-out, a\ntimeline, a loop — it can be an **explainer**: the same mascot and look\ndrawing the structure as a hand-built sketch-diagram with arrows and\ncallouts (`references/composition.md`, \"Two registers\" and \"Pick the\ndiagram type\"; editorial scene is always the default). A named pipeline\nor recipe is **labeled stages** inside that register — named phases in\norder, one connected system, pack-solved for this body, never a new look.\nOr a **character cutout**: the mascot alone on a transparent PNG for downstream overlay\n— pose and contact continuity only, no idea, no text, no environment\n(`references/cutout.md`).\n\nThis is a configurable house style, not a generic image generator. The\n**methodology is the constant**; the **character pack and palette are the\nparameters** — and a character pack carries its **style** with it: one look\nper pack, chosen from the bundled look library (riso — grainy halftone,\nink-layer offset, paper grain, one bold softly-rounded outline — plus\nblueprint, woodcut, pixel, clay, manila, chalk, phosphor, enamel,\ngouache, felt, diorama, sketchbook, bricks, fizz, bloom, and snes) or a custom style file. The default mascot is\n**Blot**, a deadpan ink-drop in riso. Palettes come\nfrom presets, the user's own palette file, or one derived color. Whatever the\nparameters, it is intentionally not a photo — with one deliberate exception, the\n`bricks` look, a toy-brick photography style — not a logo, not a corporate\ninfographic, not a formal boxes-and-diamonds flowchart look, not a UI\nmockup. Asking for a flowchart still means labeled stages in the pack's\nlook — the formality ban is a look constraint, not a refusal of the word.\n\n## Use cases — route the request\n\n| The user wants | The path |\n|---|---|\n| **Illustrate an article / post / newsletter / URL** | Steps 0–7: route the source first (thesis → coverage: hero / hero+set / set / mini-comic — `references/composition.md`, \"Source routing\"), then shot list (hero row + anchors), one image per anchor, interleave by placement. |\n| **One image for a single concept** | Step 1 concept branch (up to ~3 quick questions if the idea is thin), then a single image. |\n| **Surprise / random** — \"surprise me\", \"random\", \"surprise me with art quote using bray\", \"surprise me --autopick\" | Read `references/surprise.md` in full: Step 0 first, then character + provenance (ignore `defaultCharacter`; `* quote` forces a cited quote; else ~1/3 roll), build **three** safe candidates, interactive picker or auto-pick-best (`--autopick` preferred for schedulers), then register from the locked saying, then Steps 3–7 as one image. Deliver saying + image. Poster titles default off; mini-comics still get per-panel labels. |\n| **A sequence — story beat, before→after, fail→fix** | One **mini-comic** when the progression sits in one place (shape routing in `references/composition.md` — the idea picks the shape, the destination never does). A specified process diagram / flowchart / labeled workflow is labeled stages, not this row. |\n| **A traceable structure** — \"show the flow\", \"as labeled stages\", \"label the steps\", \"walk the stages\", \"diagram the pipeline\", \"like that factory diagram\", \"map the steps\", \"as an explainer\", or specified flowchart / labeled-workflow / process-diagram intention | The **explainer register** (`references/composition.md`, \"Pick the diagram type\" and \"The explainer register\"): a hand-built labeled-stages / flow / fan-out / timeline / loop / stack / system slice in the active look, the mascot a working part of it. Specified flowchart / labeled-workflow / process-diagram intention locks **labeled stages** in the pack's look — the formal-flowchart ban is a look constraint (no Visio, no title/legend/grid), not a refusal of the word. Labeled stages is a structure type inside explainer, not a new register or look — pack-solve it for the active character before the prompt. BEST when a unit's thesis IS a named pipeline, recipe, or staged process; never the automatic choice for every explainer. |\n| **Social-ready art for X posts / article body images** | 16:9 (or 1:1 when square is explicitly useful), bold `ink-punch`, watermark with the `x` handle if configured or asked. |\n| **X Article banner / hero image** | Use the unique banner format: **1536 × 640 px** when the user asks for an X Article hero/banner. Prompt and render through the normal `illo.py generate` image pipeline, with normal, undistorted character/object proportions and crop-safe breathing room. Do not satisfy this by manually compositing or rebuilding crops from another image unless the user explicitly asks for post-processing. |\n| **Blog / brand / site-matched art** | A named or custom palette, or derive the palette from one dominant color (`references/palettes.md`). |\n| **Their own mascot** — \"make me a character\", \"use our mascot\", \"replace Blot\" | The character builder: read `references/character-builder.md` in full and follow it end to end. |\n| **Community characters** — \"what characters are available\", \"install blip\", \"install all characters\", \"update mole\", \"publish my character\" | `references/pack-sharing.md` — engine `packs list/show/install/update`, including `packs install --all`; publish via a GitHub PR. |\n| **A different look** — \"in blueprint\", \"woodcut style\", \"pixel version of blip\" | Styles travel with character packs: build a **style variant pack** via `references/character-builder.md`, \"Style variants\". |\n| **Options to pick from, or \"which model is best\"** | Step 5b: `--count` variations or a model loop → `gallery` with a recommendation. |\n| **Fix an existing image** (stray title, recolor, mascot too decorative) | Edit prompts in `references/prompt-recipe.md`, passing the image back as `--ref`. |\n| **Character cutout / transparent PNG / overlay sticker** — \"just the mascot\", \"no background\", \"paste on something else\" | The **cutout register** (`references/cutout.md`): read in full, prompt from `references/prompt-recipe.md` \"Cutout variant\", generate with `--cutout` and `--aspect 1:1`. OpenRouter cutouts default to GPT Image 2 (not Grok). Not for explaining an idea — reroute to editorial if the ask needs a scene. |\n| **Animated idle / bot avatar / looping GIF of the mascot** | The **cutout register** plus `references/cutout.md`, \"Idle loop / bot avatar\": one transparent 1:1 cutout with `--cutout` and the character sheet as `--ref`, then programmatic motion on that PNG. |\n\n## Prerequisites\n\nThe engine (`scripts/illo.py`, stdlib Python, no installs) renders through one\nof **three engine backends** plus **two agent-side transports**; `python3` and\nnetwork access are the only hard requirements. **Grok Bot** (Cursor's Grok\nBot / the Grok desktop assistant) is an agent-side transport: use its built-in\nGrok image tool directly, not `illo.py generate`, when no user config\nexplicitly selects an engine backend. **Muse** (Meta's personal assistant,\nBlip) is the other agent-side transport: when *you* are Blip, build the illo\nprompt per this skill and call your native image-generation tool with the\nactive character sheet attached as a reference. Other agents that happen to\nexpose some image API must not take either native path — the agent must be\nable to call its own built-in image tool *and* be named above.\n\n**Running the engine — set `$SKILL_DIR` inline in each block.** Every engine\ncommand below is `python3 \"$SKILL_DIR/scripts/illo.py\" …`. Set `SKILL_DIR` to the\nabsolute path of the directory this `SKILL.md` was loaded from (it contains\n`scripts/illo.py` and `assets/`) **in the same command block that uses it** — shell\nstate does not persist between separate command runs, so a value set in an earlier\nblock is gone by the next. If the harness does not expose that path, find the\ninstalled `scripts/illo.py` and use its parent; if neither resolves, stop rather\nthan guessing the working directory. The engine self-locates its own bundled\nassets, so `$SKILL_DIR` only has to be right enough to launch `illo.py` and to\npoint `--ref` at the bundled character sheet.\n\nWrite the block **flatten-safe** — some hosts (Codex observed) collapse a fenced\nblock to one line, turning a newline into a space. Terminate the assignment with\n`;` (`SKILL_DIR=\"…\";` — without it, a flattened `SKILL_DIR=\"…\" python3 \"$SKILL_DIR/…\"`\nbecomes an env-prefix whose `$SKILL_DIR` expands to empty **before** the assignment\napplies, so the path collapses to `/scripts/illo.py`). Put **no comment on an\nassignment or command line** (a flattened `#` comments out the rest of the line and\nthe command silently vanishes), and keep each invocation on **one line** (a\nflattened `\\` continuation injects stray arguments). A wrong or unset value makes\n`doctor` (Workflow step 0) fail loudly (`can't open file …/scripts/illo.py`) — the\nsignal to fix the path, not a skill fault.\n\n- **Codex backend (free for Codex subscribers).** When the host has a usable\n  **Codex CLI** — installed, `codex login`-ed, with the `image_generation`\n  feature — illo can generate through the user's Codex subscription at no\n  per-image charge (it draws on their Codex quota). No API key, no token: illo\n  only shells out to the user's own CLI. Detected, not assumed; gpt-image-2 is\n  automatic; unsupported on Windows/WSL.\n- **Grok CLI backend (free for Grok/xAI subscribers).** When the host has a usable\n  **Grok CLI** — installed and `grok login`-ed — illo can generate through the\n  user's Grok subscription via `grok -p` (headless), drawing on their Grok\n  quota. Same env-free, token-free subprocess design as Codex. **Grok returns\n  JPEG with no alpha, so it cannot make transparent cutouts** — those auto-fall\n  back to a cutout-capable backend. The image tool exposes no model selector.\n- **Grok Bot native transport (agent-side, free for Grok Bot users).** When\n  **you are Grok Bot** — specifically Cursor's Grok Bot / the Grok desktop\n  assistant with the built-in Grok image tool — build the illo prompt and call\n  that tool with the active character's model sheet as a reference image. Do\n  not require the Grok CLI, Codex CLI, or an OpenRouter key; do not treat a\n  missing engine backend as a reason to run `init`. This is not a generic\n  \"host image API\" rule and not an `illo.py --backend` value.\n- **OpenRouter backend (paid, direct or explicit fallback).** Needs an\n  **OpenRouter API key** in the user's config file — the **single credential\n  channel** — written once by the user-run `init` (mode 600). The engine never\n  reads secrets from the environment and never accepts them as command-line\n  arguments. A host without a subscription CLI can select this engine path directly.\n  A failed Codex/Grok CLI render does **not** spend money automatically: paid\n  fallback requires `--allow-paid-fallback`. It is **model-selectable**\n  (`--model`).\n\nCapsule of the backend/transport model (resolution and precedence, the CLI\nrequirements, the Grok Bot native path, the built-in image tool being\nautomatic, quota vs. charge, cutout limits, Windows/WSL, fallback): **read\n`references/backends.md` in full before choosing or explaining a backend** —\nthe mechanics live there, once.\n\n### Setup is the user's job (never enter the key yourself)\n\nEntering an API key is something the **user** does. Do not type, paste, print,\nor store the user's key — direct them to bootstrap it:\n\n- **Bootstrap (user runs it):** `python3 \"$SKILL_DIR/scripts/illo.py\" init` —\n  prompts for the key at a hidden prompt (never echoed) and writes the\n  YAML config `${XDG_CONFIG_HOME:-~/.config}/illo/config.yaml` (mode 600). It\n  can also store non-secret defaults: `--model`, `--palette`, `--aspect`,\n  `--character`, `--watermark`. Use `--no-key` to update preferences without\n  touching the stored key. (The config is read via PyYAML when installed;\n  without it a minimal built-in parser still reads the flat keys — `apiKey`,\n  `model`, … — so generation needs no installs. Only nested settings like\n  `watermark` need PyYAML: `python -m pip install 'PyYAML==6.0.2'`.)\n- **Non-secret prefs may be seeded** for the user with the same command and\n  `--no-key`, but the key itself is theirs to enter.\n\n### Hermes Agent only: binary asset repair preflight\n\nSome Hermes versions corrupt binary files (the bundled character sheets) when\ninstalling multi-file skills from GitHub — text files survive, binaries don't,\nand a corrupted sheet silently breaks the character lock. **Under Hermes\nAgent**, run this once before first use (and whenever `doctor` reports\n`assets: CORRUPTED`):\n\n```bash\nbash ${HERMES_SKILL_DIR}/scripts/repair-hermes-assets.sh\n```\n\nIt verifies every bundled binary against known-good SHA256 hashes\n(`assets/checksums.txt`) and re-downloads only mismatched files from pinned,\nimmutable URLs — a no-op when everything checks out. Under Claude Code,\nCodex, OpenClaw, or any runtime that installs faithfully: skip this; `doctor`\nchecks asset integrity everywhere and will say if repair is ever needed.\n\n## Read these references as needed\n\nDo not load everything at once. Pull the file that matches the step:\n\n- `references/visual-style.md` — riso, the house default look: the risograph technique, line language, paper/ink, hard do/don'ts.\n- `references/styles/<name>.md` — the rest of the look library (`blueprint`, `woodcut`, `pixel`, `clay`, `manila`, `chalk`, `phosphor`, `enamel`, `gouache`, `felt`, `diorama`, `sketchbook`, `bricks`, `fizz`, `bloom`, `snes`), consumed by character packs. Read the active character's style file in full before generating.\n- `references/character.md` — the character rules (the load-bearing test, anti-complexity guardrails, value-follows-palette, the **interaction model** — declared per pack or derived conservatively from the locked design and reference sheet), the default character **Blot**, and the custom-pack format. Read before any character work.\n- `references/character-builder.md` — the guided flow for designing and installing a user's own mascot. Read in full before building or replacing a character.\n- `references/pack-sharing.md` — installing characters from the community repo and publishing a pack via PR. Read before any install/publish request.\n- `references/palettes.md` — named presets, default resolution, custom palettes, **and the derive-a-palette-from-one-color algorithm**. Read in full before choosing or deriving any palette.\n- `references/composition.md` — the two registers (editorial scene / explainer diagram), the diagram-type picker, the explainer's structure types and budget (including labeled stages, arrow notes, and its pack-solve), stagings, turning an idea into a move, the **anatomy-action feasibility gate** (validate the contact map against the character's interaction model before rendering), the no-recycled-composition rule, and the shot-list format.\n- `references/cutout.md` — the cutout register: transparent compositing assets, contact continuity, pose vocabulary, and generate flags. Read in full before any cutout request.\n- `references/surprise.md` — surprise / random mode: preflight-first, scope parse, random character, provenance variety + three saying candidates (optional parallel verify for sourced modes), interactive picker or `--autopick` / auto-pick-best, full re-roll on refresh, register after the locked saying, saying bar + sense bar, multi-source quote verification, safety-before-offer, headless contract. Read in full before any surprise/random request.\n- `references/backends.md` — the three-backend image engine plus the Grok Bot native transport: how the engine backend resolves (precedence Codex > Grok > OpenRouter, and the self-identify rule), when Grok Bot bypasses `illo.py generate`, the Codex/Grok CLI requirements, artifact-first success, the built-in image tool being automatic (no model selection), quota-vs-charge, Grok's no-cutout limit, Windows/WSL, and opt-in paid fallback. Read before choosing or explaining a backend.\n- `references/models.md` — the model lineup (**OpenRouter backend only**): friendly-name → OpenRouter id map, traits, aspect caveats, 404/fallback handling. Read before passing any `--model`.\n- `references/prompt-recipe.md` — the generation prompt template and the edit/recolor prompts.\n- `references/quality-bar.md` — the post-generation checklist and iteration rules. Read before delivering.\n\n`assets/character-reference.webp` is the default character's canonical model\nsheet — the consistency anchor (used by the engine, below); a custom pack\nbrings its own. Style-calibration examples are **not bundled** — each style\nfile links its own by URL (fetch when needed): study line density, negative\nspace, and accent restraint. **Never copy their compositions** — invent a\nfresh metaphor for the current piece.\n\n## Workflow\n\n### 0. Preflight\n\nBefore generating, confirm the engine is ready:\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" doctor\n```\n\nRun the `illo.py` call standalone — never chained with `&&` — so the displayed exit code is\nthe readiness signal itself (0 = ready): a chained neighbor's failure paints\na healthy check as an error.\n\nIt reports python, the config path, the resolved model/palette defaults,\nwhether a **custom character pack** or **custom palettes file** exists,\n**Codex/Grok CLI detection and the resolved backend/transport**, and whether an\nOpenRouter key is found (without revealing it); exit 0 = the resolved backend\nis ready. An OpenRouter-only install (no subscription CLI) stays exit 0 —\nreadiness follows the resolved backend, not a hardwired key check\n(`references/backends.md`).\n\n**Grok Bot native path (agent-side).** If you are **Grok Bot** (Cursor's Grok\nBot / the Grok desktop assistant with the built-in Grok image tool) and the\nuser has not explicitly chosen `backend: openrouter`, `backend: codex`, or\n`backend: grok`, initialize the agent-side transport before relying on\n`doctor`:\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" init --backend grok-bot --no-key\n```\n\nThen run `doctor` normally: exit 0 is meaningful readiness for this path.\nMissing Codex CLI, Grok CLI, or OpenRouter key are not failures when\n`backend: grok-bot`; corrupted assets, unreadable custom packs, malformed\npalettes, or the wrong `SKILL_DIR` still fail and must be fixed before\nrendering. Generate in Step 5 by calling Grok Bot's built-in Grok image tool\nwith the active model sheet reference. This route is only for Grok Bot's own\nGrok image tool; other agents with unrelated image tools must use the engine\nbackends below.\n\nShort path for Grok Bot: run `init --backend grok-bot --no-key` once when\nbackend is unset/auto, run `doctor` for assets/config/packs, use `packs`\ncommands normally (including `packs install --all` after install so community\ncharacters are local), read the same references, build the same prompt, then\ncall Grok Bot's built-in Grok image tool with the active character reference.\nSkip `illo.py init` for OpenRouter unless the user explicitly wants OpenRouter\nor another engine backend default, and skip `illo.py generate` unless the user\nexplicitly selected an engine backend.\n\n**Muse native path (agent-side).** If you are **Blip** (Meta's personal\nassistant, Muse) and the user has not explicitly chosen an engine backend\n(`backend: openrouter`, `backend: codex`, or `backend: grok`), initialize the\nagent-side transport before relying on `doctor`:\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" init --backend muse-native --no-key\n```\n\nThen run `doctor` normally: exit 0 is meaningful readiness for this path.\nMissing Codex CLI, Grok CLI, or OpenRouter key are not failures when\n`backend: muse-native`; corrupted assets, unreadable custom packs, malformed\npalettes, or the wrong `SKILL_DIR` still fail and must be fixed before\nrendering. Generate in Step 5 by calling your native image-generation tool\nwith the active model sheet reference. Unlike Grok Bot, this path **can** do\ncutouts: render on the pack's chroma screen and run `illo.py keyout` (see\n`references/cutout.md`). This route is only for Blip's own native image tool;\nother agents with unrelated image tools must use the engine backends.\n\nShort path for Muse: run `init --backend muse-native --no-key` once when\nbackend is unset/auto, run `doctor` for assets/config/packs, use `packs`\ncommands normally, read the same references, build the same prompt, then call\nyour native image tool with the active character reference. Skip\n`illo.py generate` unless the user explicitly selected an engine backend —\nfor a native render, record it with `illo.py record` (or `keyout` for\ncutouts) so it joins the run's `manifest.jsonl` and galleries.\n\n**Config migration — surface the backend choice interactively.** When you are\ngoing to use `illo.py generate`, if `doctor` reports `backend: NEEDS CHOICE`\n(or `generate` hard-stops saying the config \"is out of date\"), this user's\nconfig predates the backend choice — they have an older install and have never\nbeen offered a subscription CLI. Do **not** pick for them silently. Surface an\n**interactive choice** using the platform's\nblocking-question capability (`AskUserQuestion` in Claude Code, the equivalent\nelsewhere; where the host has none — e.g. a plain chat session — ask the same one\nchoice as a concise message and wait for the reply, never picking silently):\n\"illo now has image backends/transports — which would you like?\" with five\noptions — **Codex** (free, your Codex subscription), **Grok CLI** (free, your\nGrok subscription; no transparent cutouts), **Grok Bot** (agent-side native\ntool; use only when you are Grok Bot), **Muse** (agent-side native tool; use\nonly when you are Blip, Meta's personal assistant), and **OpenRouter** (pick\nthe model: Grok Imagine, Nano Banana, GPT Image, and others). Persist the answer without\ntouching any existing key:\n`python3 \"$SKILL_DIR/scripts/illo.py\" init --backend <codex|grok|grok-bot|muse-native|openrouter> --no-key`,\nthen continue. A brand-new install (no config at all) is ordinary onboarding,\nnot this migration — it does not fire.\n\n**Prefer your own CLI when you are a subscription-CLI agent.** The engine's\nauto-default reads *host* capability (**Codex > Grok > OpenRouter**; it can't\ntell which agent invoked it) — but **you know which agent you are**. So when you\nare a subscription-CLI agent and your own CLI is usable on this host, add your\nown backend flag to `generate` for non-cutout renders: the **Grok CLI agent**\nadds `--backend grok`, the **Codex agent** adds `--backend codex`. This keeps\n\"in Grok CLI, generate with Grok\" true even on a host that also has Codex, with\nno runtime-sniffing in the engine. Cutouts ignore this (Grok can't make them —\nthey auto-fall back). A user's config `backend:` overrides everything.\nResolution and precedence mechanics: `references/backends.md`.\n\nFor Grok Bot, the equivalent self-identify rule happens **before** `generate`:\nwhen backend is unset/auto, persist `backend: grok-bot` with\n`init --backend grok-bot --no-key` and use the native Grok image tool path\nabove. If the user explicitly configured or requested an engine backend, honor\nthat choice instead of silently switching to Grok Bot native.\n\nFor Blip (Muse), the equivalent rule is the same: when backend is unset/auto,\npersist `backend: muse-native` with `init --backend muse-native --no-key` and\nuse the native image tool path. If the user explicitly configured or requested\nan engine backend, honor that choice instead of silently switching to Muse\nnative.\n\nRead the printed **config path** before concluding\nthe key is missing: under Hermes,\nmulti-profile setups can resolve `HOME`/`XDG_CONFIG_HOME` to *another*\nprofile's home (e.g. `…/profiles/<name>/home/.config/illo/…`), so a key\nthat exists looks absent. If the path points at the wrong profile, re-run\nwith the right `HERMES_HOME`/`HOME`/`XDG_CONFIG_HOME` rather than treating\nthe key as missing. If the key is genuinely\n**missing**, stop and ask the user to run\n`python3 \"$SKILL_DIR/scripts/illo.py\" init` themselves — do not enter the\nkey for them. In a **chat session** the user can't run commands where they\nare, so shrink their host-side step first: run `init --no-key` yourself\n(allowed — it scaffolds the config with defaults and a commented `# apiKey:`\nplaceholder, mode 600, never touching a key), then offer the user two\nequivalent one-time options **on the machine the agent runs on** (that host\nis theirs — it's where they installed the agent): run\n`python3 <resolved absolute $SKILL_DIR>/scripts/illo.py init` (hidden\nprompt), or open `~/.config/illo/config.yaml` and fill in the `apiKey:`\nline. The key must never transit the chat: never ask for it in a message,\nand if the user pastes it anyway, do not use it — tell them to revoke that\nkey at openrouter.ai and set a fresh one on the host (the pasted key now\nlives in chat history and platform servers). Never copy a key from the\nenvironment or any other store into the config yourself — the user is the\nonly writer of that line — with **one scoped exception**: an ephemeral\ncloud workspace (Claude Code web, Codex cloud, CI) where the user\nprovisioned `OPENROUTER_API_KEY` through the platform's secrets mechanism.\nThat provisioning is itself the user's deliberate, workspace-scoped\nconsent, and there is no interactive prompt or persistent home for `init` —\nso there, seed the config from the workspace secret once (the \"Cloud & CI\"\none-liner in README.md). On a personal machine an ambient env var proves\nnothing about intent (it may belong to other tools) — the rule stands:\nnever copy it.\n\n**Optional pack-freshness offer (preflight, consent-first).** When this run\nwill render with an installed community pack (`doctor` lists packs; installs\ncarry a `.version` stamp), optionally check freshness:\n`python3 \"$SKILL_DIR/scripts/illo.py\" packs list` flags stale installs\n(`[installed 1.0.0 — 1.0.2 available]`). The check may run here, but the\n**offer fires once the active pack is known** — after Step 2 resolves the\ncharacter (or after surprise mode's character roll), immediately before\nthe first render that uses it. If that resolved pack is stale, offer\n**once** — via the platform's blocking-question capability, as\nin the config migration above — to refresh it before rendering, and run\n`packs update <name>` only on an explicit yes (updating overwrites the\nlocal copy; the hand-edit warning and `--as` alternative are in\n`references/pack-sharing.md`). Never update silently, and never block on\nthis: a \"no\", an offline host, a registry error, or a headless/scheduler\nrun (e.g. surprise `--autopick`) all continue with the pinned copy — a pack\nwithout a declared `## Interaction model` still plans safely via the\nconservative derivation (`references/character.md`). Skip the check\nentirely when no community-installed pack is involved.\n\n### 1. Read the input — and clarify a thin concept (briefly)\n\nThree kinds of input, handled differently:\n\n- **Surprise / random** (\"surprise me\", \"random\", \"surprise me with art quote\n  using bray\", \"surprise me --autopick\", and close variants) — the ask is\n  invent-and-render, not a supplied thesis. **Stop and read\n  `references/surprise.md` in full**, run Step 0 first, then resolve character\n  and provenance there (ignore `defaultCharacter`; random character when\n  unnamed), build three saying candidates and lock one via picker or\n  auto-pick-best, pick register from the locked saying, then continue Steps\n  3–7 as one image — Steps 0 and 2 are skipped in that render pass because\n  preflight and pack are already done. Do not enter the thin-concept Q&A path\n  below. A prompt that already names a concrete idea (\"illustrate 'you are\n  the bottleneck'\") is **not** surprise mode even if it also says \"surprise\n  me\".\n- **A URL / article / paste / long post** carries its own context — but\n  never generate from the first vivid detail. Route it first\n  (`references/composition.md`, \"Source routing\"): classify the source's\n  **shape and genre**, infer the **requested artifact's job** (what this\n  image must do for its audience), separate that job from the source's most\n  drawable mechanism, **lock the main thesis in one sentence** (a hero locks\n  the source/artifact job, not its loudest evidence — the genre guardrails\n  say what each genre heroes), then pick the coverage — hero, hero +\n  per-section set (the full article job), set, mini-comic, or shot list\n  first. Sets need placements: compact sources (a tweet, one\n  concept) never yield a set — their multi-beat form is the mini-comic. Pull the **load-bearing moments** —\n  the few places that turn on a judgment, a loop, an input→output, a\n  before/after, or a trap — never one image per paragraph. The text already\n  says what it's about, so don't interrogate the user, with **one\n  exception**: a materially multi-beat source (long article, postmortem,\n  multi-claim launch) gets a single coverage question before any\n  multi-image spend — unless the user already named the coverage. A lone\n  image from a multi-beat source is a **hero**, delivered saying so — not\n  as coverage of the piece.\n- **A bare concept or one-liner** (e.g. \"illustrate 'you are the bottleneck'\")\n  usually underspecifies the picture. Ask **up to ~3 quick questions — only the\n  ones that change the output — then build.** Draw from:\n  - the single takeaway (what should the reader conclude?),\n  - where it's headed (blog / deck / X post / X article body / X Article banner → sets palette, aspect, pixel normalization, and watermark),\n  - the shape: one image (the default), a **mini-comic** (2–4 panels in one\n    image — only when the idea itself advances through stages), or several\n    separate images — plus any must-include element or constraint. The shape\n    follows the idea, never the destination (`references/composition.md`).\n\n  Keep it to **one short round**, then proceed. **Skip the questions entirely**\n  if the user already gave enough, said \"just make it\" / \"single shot\", or\n  the answer is obvious from context. Never block a clear request by asking.\n\n### 2. Resolve the character\n\n**Surprise / random mode:** skip this step — character was already resolved\nin `references/surprise.md` (named pack, or random among installed + Blot;\nnever `defaultCharacter`). Continue at Step 3+.\n\nInstalled packs live under `${XDG_CONFIG_HOME:-~/.config}/illo/characters/`\n(format and location details: `references/character.md`); `doctor` lists\nwhat's installed. A user can keep several and pick per run. First match\nwins:\n\n1. **Explicit request** — \"use <pack name>\", \"as <name>\": that pack (or the\n   shipped default when asked for by name, `blot`). When the word matches no\n   pack name, resolve by **approximation**: match it against each installed\n   pack's `Aliases:` line and subject (the `character.md` opening line and\n   Locked design **Body**) — `doctor` prints names + aliases, so this needs\n   no file reads in the common case — and against catalog `description`s\n   (`packs list`). So \"use ox\" finds a pack subtitled an ox (e.g. `yoke`).\n   On one clear match, use it and name it; on several, ask which; on none,\n   say so before falling through.\n2. **Config default** — `defaultCharacter` from the user config, if set.\n3. **Shipped default** — **Blot** (spec in `references/character.md`, model\n   sheet `assets/character-reference.webp`).\n\nOnce resolved, read the pack's `character.md` and use its prompt spec, value\nrules, optional **`Cutout chroma:`** compatibility preference, and\n`reference.png` everywhere the default's would be used.\n\nWhen rerouting an article set to a new character — especially after a weak\nattempt, or for a technical/platform essay — read\n`references/article-set-character-reroute.md` in full before planning or\nrendering. Do the legibility preflight there before spending renders.\n\nIf the user wants a *new* character, that is the character builder\n(`references/character-builder.md`); if they want someone else's, packs\ninstall from the community repo (`references/pack-sharing.md`). Either way,\ninstall first, then continue here.\n\n### 3. Plan (shot list) — when asked to plan, or for anything multi-image\n\nIf the user wants planning (\"where should this be illustrated\", \"shot list\"),\noutput a shot list before generating. Per image: placement, the one idea,\nthe artifact job, the register (editorial unless the row passes the explainer\ngate), the staging (or structure type — pick per `references/composition.md`,\n\"Pick the diagram type\"), **what the mascot is doing**, the\npalette, and the text hierarchy — primary read/title when the artifact needs\none, plus short supporting labels/callouts within the per-register budgets in\n`references/composition.md`. Let the anchor count drive how many (bands and the never-pad\nrule are in `references/composition.md`). When a stretch of the piece advances\nthrough stages **in one place**, plan a single mini-comic image there instead\nof several — the mini-comic-vs-separate routing is in\n`references/composition.md`.\n\nFor article-set character reroutes, add the mandatory preflight fields from\n`references/article-set-character-reroute.md` before any render: section claim,\nvisual object/action, and reader mapping. Reject rows that need a private\nmetaphor glossary or more than one conceptual substitution.\n\n### 4. Resolve the palette (the style is the character's)\n\n**Style** is not separately resolvable: the active character's pack carries\nit — the `Style:` line in its `character.md` names a bundled look\n(`references/styles/<name>.md`, riso in `visual-style.md`) or a custom one at\n`${XDG_CONFIG_HOME:-~/.config}/illo/styles/<name>.md`; absent line = riso.\nBlot is riso. For any non-riso style, read its file in full: it supplies the\nSTYLE and LINE LANGUAGE prompt blocks, the palette mapping, the character\ntreatment, and extra QA checks. A request for the same character in a\n*different* look is a variant-pack build (route table) — never restyle on the\nfly.\n\n**Palette**: read `references/palettes.md` in full and resolve there — it\nholds the resolution order (explicit request, then destination cue via the\nuser's palettes file, then config default, then house `ink-punch`), the named\npresets, custom palettes, and the derive-a-palette-from-one-color algorithm.\nEnd with **concrete hex values**; when the pack's style isn't riso, run them\nthrough that style's palette mapping.\n\n### 5. Generate — reference-locked, one metaphor per image\n\n**Cutout branch.** When the request routed to the cutout register, read\n`references/cutout.md` in full first — it covers backend-aware transparency\n(Codex native alpha by default; chroma compatibility for OpenRouter or explicit\n`--chroma`), **registration-locked silhouette** (no ink-layer offset),\n**`--cutout`** /**`--aspect 1:1`**, OpenRouter **`--image-config`**, and manifest\n**`cutout_alpha`** disclosure. Build the prompt from\n`references/prompt-recipe.md`, \"Cutout variant\" — not the editorial template —\nand omit manual `BACKGROUND:` / output-format instructions; the engine appends\nthe contract for the backend that actually runs. Pass `--chroma` only to force\na compatibility reroll. Use only the character model sheet as `--ref` (no\neditorial style anchor, no watermark). QA against the cutout section of\n`references/quality-bar.md`. Skip the editorial shot-list / thesis steps.\n\n**Editorial and explainer.** When the locked type is labeled stages, run the\npack-solve scratch in `references/composition.md` (\"Labeled stages — skeleton,\nthen pack-solve\") before writing the prompt — stage list → operator\nstage → contact map → bind; do not invent a look. Build a full prompt per\nimage from\n`references/prompt-recipe.md` (scene + structure + communication hierarchy +\nstyle + the active character's spec + resolved palette hexes + the\nper-register text budget), write it to a file, and render it. **Pass the active character's\nmodel sheet as `--ref` every time** — that reference conditioning is what\nkeeps the mascot on-model; style and palette come from the prompt, so both\nstays swappable. A pack's sheet is born in its own style, so sheet and style\nalways match — no cross-style reference juggling. (Under Hermes Agent, the\nasset-repair preflight above must have run before the first `--ref` use —\na corrupted sheet conditions every render on garbage.)\n\n**Grok Bot native render.** If you are Grok Bot and the native path from Step 0\napplies, do **not** run `illo.py generate`. Use the same full prompt recipe,\nsame aspect ratio, same character lock, same style-anchor rule for sets, and\ncall Grok Bot's built-in Grok image tool. Attach the active character's model\nsheet as a reference image (`assets/character-reference.webp` for Blot, or the\npack's `reference.png`); for later images in a set, also attach the accepted\nstyle anchor image. Ask the tool to save/return the generated file and treat\nthat saved path as the engine JSON `.path` equivalent for QA and delivery.\nGrok Bot's image tool is the same Grok image-model class as the Grok CLI\ntransport: no model selector, no OpenRouter billing, and no alpha channel.\nTransparent cutouts stay off this path; route them to a cutout-capable engine\nbackend instead, or stop and ask for that backend to be configured.\n\n**Muse native render.** If you are Blip (Meta's personal assistant, Muse)\nand the native path from Step 0 applies, do **not** run `illo.py generate`.\nUse the same full prompt recipe, same aspect ratio, same character lock, same\nstyle-anchor rule for sets, and call your native image-generation tool.\nAttach the active character's model sheet as a reference image\n(`assets/character-reference.webp` for Blot, or the pack's `reference.png`);\nfor later images in a set, also attach the accepted style anchor image. Up to\nfour native image calls may be batched in one response — beyond that, continue\nin a follow-up. Save each returned file under the run dir, then record it with\n`illo.py record` (see its usage), which appends a `muse-native` manifest row\nwith the label and prompt so it joins galleries like engine renders. Treat\nthe recorded path as the engine JSON `.path` equivalent for QA and delivery.\n\nUnlike Grok Bot, this path **can** do cutouts: ask the native tool for the\npack's flat chroma screen (the pack declares `green` or `magenta`), then run\n`illo.py keyout <screen.png> --chroma <green|magenta> --out <final.png>` to\nproduce a transparent PNG — see `references/cutout.md` for the chroma\nselection, QA, and the opaque-fallback rule. There is no model selector and\nno OpenRouter billing on this path; `--model` does not apply.\n\nSet `SKILL_DIR` inline (see Prerequisites), and use the bundled sheet as `REF` — or\nthe active pack's `reference.png` for a custom character. Add `--model <id>` to\noverride the config/default model for this image (OpenRouter backend only):\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\nREF=\"$SKILL_DIR/assets/character-reference.webp\";\npython3 \"$SKILL_DIR/scripts/illo.py\" generate --prompt-file /tmp/shot-01.txt --ref \"$REF\" --aspect 16:9 --out \"assets/<slug>-illustrations/01-topic.png\"\n```\n\nFor engine renders, `illo.py generate` prints a **JSON line per image**\n(`{path, backend, model, id, cost, width, height, label, prompt}`; `backend` is\n`codex`, `grok`, or `openrouter`, and `model`/`id`/`cost` are OpenRouter-only —\nthey are null on a CLI-served record (Codex or Grok). `cost` is null unless\n`--cost` is passed — `gallery` backfills it) and appends the same record to\n`<out-dir>/manifest.jsonl`.\nRead `.path` — it may differ from `--out`: the engine names the file by the\nactual encoding (some models return JPEG bytes, so a requested `.png` lands\nas `.jpg`). Use `.width/.height` to catch a square when 16:9 was requested\n(re-roll). A failed Codex/Grok CLI render stops by default even when an OpenRouter\nkey is configured. Add `--allow-paid-fallback` only when the user has explicitly\napproved a pay-per-image retry. Direct `--backend openrouter` renders and the\nintentional Grok-cutout redirect remain direct routes and do not need this flag.\nGenerate each image **separately** — never combine ideas into one canvas. Default\naspect is 16:9; use `1:1` for square social, `9:16`/`4:5` for vertical, and\n`1536:640` for an **X Article banner / hero**. For X Article banners, the\nplatform target is **1536 × 640 px**. Generate through the normal image\npipeline; do not manually composite or rebuild the scene from crops as a\nsubstitute for an illo render. Check `.width/.height`, and only do final\npost-processing when it is a non-distorting resize/crop that preserves normal\nproportions and all essential information. Never stretch or squash the art to\nforce exact dimensions. Pass `--label` for a caption that shows in the gallery.\n\n**Sets read as one artist.** For any multi-image set, the first image that\n**passes the full quality bar** (and, for a hero in a rerouted article set,\npasses the thesis-legibility gate in\n`references/article-set-character-reroute.md`; never anchor on an unvetted\nrender — a failed anchor, e.g. an off-palette ground or illegible metaphor,\nwould propagate its failure set-wide) becomes the set's **style anchor**: pass\nit as a second `--ref` after the character sheet for every later image in the\nset and for every re-roll of a set member, so line weight, halftone density,\nand flat-vs-dimensional treatment stay consistent throughout. The same trick\nlocks style for a one-off: add any finished example as a second `--ref`.\n\n**Model choice (OpenRouter backend only).** `--model` and config `model:` are\nan **OpenRouter-only** axis — on Codex, Grok CLI, Grok Bot native, and Muse\nnative the image model is automatic and `--model` does not apply (`references/backends.md`). For\nthe OpenRouter path, read `references/models.md` in full before passing any\n`--model` (or whenever the user names a model in plain language or asks for\n\"best quality\" / \"cheapest\"): it holds the friendly-name → OpenRouter id map,\nper-model traits, the aspect-ratio caveat, and the 404/fallback handling.\nResolution is `--model` > config `model` > built-in default.\n\n**Watermark / attribution (optional, off by default).** The skill ships with\n**no** default watermark — the text comes only from the user's `watermark`\nconfig map (read from the config file) or an explicit request, so installers\nnever inherit someone else's handle. The resolution order, the prompt line to\nappend, and the two-render caveat are in `references/prompt-recipe.md`.\n\n### 5b. Batches & comparison (only when it helps)\n\n**Default to ONE image.** Fan out only when the user asks for options/comparison\nor the piece is important enough to be worth it — and **say first what each\nimage costs**: on the Codex backend it draws on the user's Codex quota (no\nper-image charge), on Grok CLI or Grok Bot native it draws on the user's Grok\nquota, on Muse native it uses the agent's built-in image tool (no OpenRouter\nbilling), and on the OpenRouter backend it bills their OpenRouter account\n(typically under ten cents per image, varying by model). Keep N small (2–4).\nOrchestrate the loop with the engine's primitives:\n\n`newrun` prints a fresh run dir (`/tmp/illo/<runid>`) into `RUN`. Record the user's\nVERBATIM request (URL, pasted text, concept) to `request.txt` — the gallery shows\nit as provenance so anyone can tell what the run was for. Adapt each `generate`\nline below to a real path and run it on its own:\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\nRUN=$(python3 \"$SKILL_DIR/scripts/illo.py\" newrun);\nprintf '%s' \"<the verbatim request>\" > \"$RUN/request.txt\"\n# (a) VARIATIONS — same prompt+model, pick-the-best:\npython3 .../illo.py generate --prompt-file p.txt --ref <ref> --count 4 --label \"draft→ship\" --out \"$RUN/v.png\"\n# (b) MODEL COMPARISON — loop the SAME prompt over the chosen models\n#     (full OpenRouter ids from references/models.md):\nfor m in <model-id-1> <model-id-2>; do\n  python3 .../illo.py generate --prompt-file p.txt --ref <ref> --model \"$m\" --label \"$m\" --out \"$RUN/$(basename $m).png\"; done\n# (c) CONCEPT VARIATIONS — different prompts (different stagings) for one idea:\npython3 .../illo.py generate --prompt-file staging-A.txt --ref <ref> --label \"as a funnel\" --out \"$RUN/a.png\"\npython3 .../illo.py generate --prompt-file staging-B.txt --ref <ref> --label \"as a crossing\" --out \"$RUN/b.png\"\n\npython3 \"$SKILL_DIR/scripts/illo.py\" gallery \"$RUN\" --title \"<the piece or request>\" --open\n# always pass --title so a saved gallery stays identifiable later;\n# add --embed for a single portable file (images inlined)\n```\n\nEvery `generate` self-records to `$RUN/manifest.jsonl`; `gallery` assembles them\ninto one page with each image's **label, model, dimensions, cost, and a\ncollapsible prompt** — the prompt toggle is what makes concept-variation\ncomparison readable (the prompt is the variable). Always present the gallery\n**with a recommendation**, not a raw dump — and in a chat session, present\nthe labeled candidates directly in the chat instead of a gallery (delivery\nrouting in step 7). Multi-model failures are per-image\n(an unavailable model errors that one render only); keep the rest.\n\n### 6. QA and iterate\n\nCheck every image against `references/quality-bar.md`. Re-roll or edit when the\nmascot is decorative or off its locked spec, the body is wrong-value for the\npalette, label text sits on a colored fill, the accent has spread past the\ncharacter's accent part + 1–2 elements, an unwanted title bar appears, the\ncomposition copies an example, or text is misspelled. Subject scale varies\nrun-to-run — re-roll if the subject is tiny (check `.width/.height` in the\nJSON: a square back when 16:9 was requested → re-roll). When a re-roll\nsupersedes a render, rebuild any delivery gallery with\n`--exclude <superseded label>` (repeatable) so rejected rolls don't appear in\nthe review artifact.\n\n### 7. Deliver — match the session's medium\n\nCopy finals next to the user's work when appropriate; never overwrite\nexisting assets without being asked. **Filenames carry the role** — they\nare the only metadata that survives a document attachment, so make them\nself-identifying: `00-hero-<slug>.png` for the hero, then\n`01-<section-slug>.png`, `02-<section-slug>.png`, … for anchors in piece\norder (`assets/<slug>-illustrations/`). Then report: how many images, the\npalette used, which are strongest vs optional — and for any multi-image\njob, a **placement map**: one line per image naming the file, its role\n(hero, or after which section), and the one idea it lands, so the user can\ndrop each file where it belongs without re-deriving the plan. Deliver the\nimages themselves the way this session can actually show them:\n\n- **Filesystem sessions** (IDE/terminal agents — Claude Code, Codex,\n  Cursor): report each final's **absolute path** (the engine's JSON `.path`\n  is already absolute) and present the gallery for multi-image runs. The\n  file on disk already *is* the original — never emit `[[as_document]]`\n  here: it's a Hermes gateway token, literal noise in any other runtime.\n  If the runtime has its own in-chat file delivery, use that.\n- **Grok Bot native sessions:** deliver the file returned by Grok Bot's\n  built-in image tool inline/as an attachment in chat, and include its saved\n  file path in the same role that engine renders use `.path`. The returned\n  file is the original for this transport; do not ask the user to configure\n  OpenRouter just to retrieve it.\n- **Muse native sessions:** deliver the file returned by your native image\n  tool as a `sandbox://workspace/...` link in chat, and include its saved\n  file path in the same role that engine renders use `.path`. Record every\n  delivered image with `illo.py record` (or `keyout` for cutouts) so the\n  run's `manifest.jsonl` and galleries stay complete. The returned file is\n  the original for this transport; do not ask the user to configure\n  OpenRouter just to retrieve it.\n- **Chat sessions** (the user is on a messaging surface — Hermes over\n  Telegram/Discord/WhatsApp, or any chat surface with lossy media delivery —\n  and cannot open local files): a path alone is not a complete deliverable;\n  the image must land **in the chat**, and a *final* must arrive as the\n  **original file**. Platform photo delivery recompresses images — exactly\n  what destroys riso grain, halftone texture, ink-layer offset, a\n\nFile v0.37.0:README.md\n\n# Illo\n\n**[illo-skill.com](https://illo-skill.com)** — live examples, character packs,\nand copy-paste installs. This file is the developer reference (engines,\nmodels, cost, API keys).\n\nTurn a concept or an article into original **editorial illustrations** —\nflat, bold-lined print-style scenes where a recurring mascot performs the\nidea. One image says one thing: a key judgment, a flow, a before/after, a\ntrap. It's a deliberate house style, not a generic image generator — closer\nto a smart, deadpan print zine than to clip art or an infographic.\n\nThe methodology is the constant; **the character pack and palette are yours\nto set** — and every character pack carries its own print style. Out of the\nbox the mascot is **Blot**, a deadpan ink-drop in **risograph**. A built-in\n**character builder** designs your own mascot with you (interview — including\npicking its look from the bundled library of seventeen ([below](#looks)) — then\nmodel-sheet candidates → pick → install). Want the same\ncharacter in another look? Build a *style variant pack* (`blot-woodcut`):\none pack, one look, so a catalog of characters never turns into a grid of\ncombinations. Palettes stay per-image and resolve by **destination**: a\ncharacter defines *where* its accent lives, never the color. One plain-text\nline in your palettes file — `blog → notes` — and anything headed for your\nblog automatically wears `notes`, a palette built once by copying your\nsite's real CSS colors into hexes (background → paper, text → ink, link\ncolor → accent; re-extract only if you rebrand). Same mascot, fluoro pink\non X, your blog's exact orange on the blog — never asked twice. Or pick a\nnamed preset, or hand it one brand color and let it derive the rest.\n\n![Blot — the default mascot](assets/character-reference.webp)\n\n> **Invoking:** the skill answers to its name — say **\"illo\"** (\"illo this\n> post\", \"use illo: draw blip hauling a crate\"). It deliberately won't hijack\n> generic requests like \"illustrate this post\", and it can't know your\n> installed characters' names up front — lead with \"illo\", then talk\n> characters freely.\n\nSame character, different voice — the bundled woodcut style telling a\nthree-panel story:\n\n![Woodcut mini-comic example](https://raw.githubusercontent.com/tmchow/illo-skill/main/_assets/illo/styles/woodcut-minicomic.png)\n\nAnd the day job — compressing an abstract concept into one scene that lands\nin about a second. Hand it *\"we replatform with zero downtime\"* and you get\nthe bridge being rebuilt under live traffic:\n\n![Zero downtime — rebuilding the bridge under live traffic](https://raw.githubusercontent.com/tmchow/illo-skill/main/_assets/illo/05-bridgeswap-ink-punch.png)\n\nOne idea per image, the mascot *performing* the move rather than decorating\nit, a few short hand-lettered labels — every render is held to that\nbar, and off-model results get re-rolled before you see them.\n\n## Looks\n\nEvery character pack picks exactly one look from the bundled library:\n\n| Look | The voice |\n|---|---|\n| **riso** | Grainy halftone risograph — the house default |\n| **blueprint** | White draftsman linework on deep blueprint blue |\n| **woodcut** | Heavy carved relief print on warm cream |\n| **pixel** | Chunky 4-color pixel art |\n| **clay** | Matte stop-motion plasticine diorama |\n| **manila** | Rubber-stamped ink on office manila paper |\n| **chalk** | Dusty chalk on a deep slate board |\n| **phosphor** | Glowing CRT trace on near-black glass |\n| **enamel** | Hard-enamel pin cells with raised metal lines |\n| **gouache** | Flat matte mid-century poster paint |\n| **felt** | Layered hand-cut wool-felt craft |\n| **diorama** | Watercolor-and-ink storybook tabletop diorama |\n| **sketchbook** | Vintage sepia pencil-and-ink editorial sketch |\n| **bricks** | Photoreal toy-brick set — the one photographic look |\n| **fizz** | Psychedelic soda-pop skate-sticker screenprint |\n| **bloom** | Flat cel character in a soft, atmospherically-lit cozy scene |\n| **snes** | 16-bit console sprite editorial with soft dither and game-world staging |\n\nLooks are shared infrastructure, deliberately separate from characters: the\ndefinitions live in this skill (`references/styles/`), and a character pack\njust names one — so a fix to a look immediately improves every pack that\nuses it, and adding a character never requires touching the skill. Want a\nlook that doesn't exist? Drop a custom style file in\n`~/.config/illo/styles/<name>.md` and use it right away — and if it proves\nout, PR it into the library here so packs everywhere can reference it.\n\n## Prerequisites\n\nImages are generated by a small bundled script (`scripts/illo.py`) through one\nof **three engine backends** — `python3` (standard library only, macOS/Linux)\nand network access are the only hard requirements. In **Grok Bot** (Cursor's\nGrok Bot / the Grok desktop assistant), illo instead uses Grok Bot's built-in\nGrok image tool as an agent-side transport when no engine backend is explicitly\nconfigured:\n\n- **Codex (free for Codex subscribers).** If you already have the\n  **[Codex CLI](https://github.com/openai/codex)** installed and logged in\n  (`codex login`), illo can generate through your Codex subscription at no\n  per-image charge — it draws on your Codex usage quota instead. No API key\n  and no token: illo only shells out to your own CLI. Detected automatically;\n  gpt-image-2 is the model (no model selection); unsupported on Windows/WSL.\n- **Grok (free for Grok/xAI subscribers).** If you have the **Grok CLI**\n  installed and logged in (`grok login`), illo can generate through your Grok\n  subscription via its built-in image tool, drawing on your Grok usage quota —\n  same key-free, token-free design as Codex. Handy when illo runs inside the\n  Grok agent. Two limits: no model selection, and **no transparent cutouts**\n  (Grok returns JPEG with no alpha) — cutouts auto-fall back to Codex or\n  OpenRouter.\n- **Grok Bot native (agent-side).** In Cursor's Grok Bot / the Grok desktop\n  assistant, the skill instructions route generation to Grok Bot's own built-in\n  Grok image tool with the character sheet attached as a reference. This is not\n  the Grok CLI lane and not a generic host-image-tool fallback: no `grok`\n  binary, Codex CLI, or OpenRouter key is required unless you explicitly choose\n  one of the engine backends.\n- **OpenRouter (paid, direct or explicit fallback).** An\n  **[OpenRouter](https://openrouter.ai) API key** lets illo call OpenRouter's\n  image API directly — the engine path on a host without a subscription CLI.\n  **Model-selectable** — see [Models & cost](#models--cost) below. A failed\n  Codex/Grok CLI render never spends money automatically: pass\n  `--allow-paid-fallback` to explicitly permit that pay-per-image retry.\n  Intentional cutout routing remains automatic.\n\n### Setting the key (OpenRouter path)\n\nFor the OpenRouter backend, bootstrap the config file once — you type the key\nat a hidden prompt, and nothing else ever reads or stores it. (The Codex, Grok\nCLI, and Grok Bot native paths need no OpenRouter key; `init` offers CLI\nbackends when a usable CLI is detected.)\n\n```bash\npython3 scripts/illo.py init                  # prompts for the key (hidden),\n                                              # writes ~/.config/illo/config.yaml (mode 600)\npython3 scripts/illo.py doctor                # check readiness\n```\n\nThe config file is the **only** place the engine reads the key from —\ndeliberately: no environment variables (skill security scanners treat\nsecret-shaped env reads in community skills as exfiltration) and no\n`--api-key`-style flags (command-line secrets leak into process listings\nand shell history). The config (a commented\n`config.yaml`) also holds non-secret defaults — `model`, `defaultPalette`,\n`defaultCharacter`, `aspect`, and an optional `watermark` map for\nattribution.\nThere is **no built-in watermark**; set your own so it's only ever yours:\n\n```bash\npython3 scripts/illo.py init --no-key \\\n  --watermark blog=yoursite.com --watermark x=@yourhandle\n```\n\n> The config file is read via **PyYAML** when installed\n> (`python -m pip install 'PyYAML==6.0.2'`); without it a minimal built-in\n> parser still reads the flat keys (`apiKey`, `model`, …) — only nested\n> settings like `watermark` need PyYAML. Either way, image generation\n> itself needs no installs.\n\n### Cloud & CI environments\n\nIn ephemeral workspaces (Claude Code on the web, Codex cloud, GitHub\nActions, devcontainers) there's no interactive prompt and the home\ndirectory doesn't persist — there, use the platform's own secrets\nmechanism: add `OPENROUTER_API_KEY` to the environment's secrets, and\nmaterialize the config in the environment's **setup hook** (Codex\nenvironment setup script, devcontainer `postCreateCommand`, a CI step):\n\n```bash\nmkdir -p ~/.config/illo\nprintf 'apiKey: \"%s\"\\n' \"$OPENROUTER_API_KEY\" > ~/.config/illo/config.yaml\nchmod 600 ~/.config/illo/config.yaml\n```\n\nThe key stays in the platform's secret store; each fresh workspace gets\nits config rebuilt at setup time, and the engine still reads only its\nown file. Adding the secret to the environment is the consent — it's\nscoped to that workspace and provisioned by you, deliberately, for the\ntools running there.\n\n## Models & cost\n\nCost depends on the transport. On **Codex**, **Grok CLI**, and **Grok Bot\nnative** there is **no per-image charge** — generation runs on your Codex or\nGrok subscription and draws on that quota (image turns consume it faster than\ntext turns), and the image model is automatic (no model selection). On the\n**OpenRouter** backend generation is **pay-per-image through your OpenRouter\naccount** — typically **under ten cents per image**, and a typical blog post\n(3–6 finals plus a few re-rolls) lands well under a dollar on the default model.\nPrices are\nOpenRouter's and drift — check\n[openrouter.ai/models](https://openrouter.ai/models) for current numbers. The\nmodel table below applies to the OpenRouter backend.\n\n| Model | Why you'd pick it | Relative cost |\n|---|---|---|\n| **Grok Imagine** — *default* | The recommendation comes from testing, not loyalty: boldest riso texture, the strongest character lock from the reference sheet, honors 16:9 — and the cheapest of the set. | $ |\n| Nano Banana 2 | The dependable fallback: fast, the most reliable label text, publicly catalogued. | $ |\n| Nano Banana Pro | Richest detail — worth it for hero images. | $$ |\n| GPT Image 2.5 Flare | Fast OpenRouter Images API option for generation and reference-guided edits; see the [Flare details](references/models.md#flare-through-openrouter). | $$ |\n| GPT-5.4 Image 2 | Strong instruction-following, but pricey and tends to return square regardless of the requested aspect. | $$$ |\n\nWorth knowing:\n\n- **The Grok default is API-reachable but not in OpenRouter's public model\n  list** — it works for accounts with access. If a render 404s with \"no\n  endpoints found\", the skill knows to fall back to Nano Banana 2.\n- Any other OpenRouter **image-output** model works too — name it in the\n  request (\"use Nano Banana Pro for the hero\") and the skill maps it. Ask\n  for a model comparison and it renders the same prompt across models into\n  a side-by-side gallery with per-image costs.\n\n## Install\n\nPrefer the native lane for your runtime: it installs the same `illo` skill and\nkeeps you on that platform's managed update path. The generic skills CLI is\nthe fallback for runtimes without a native plugin/skill manager.\n\n| Platform | Install | Update |\n| --- | --- | --- |\n| **Claude Code** | `/plugin marketplace add tmchow/illo-skill` then `/plugin install illo@illo-skill` | `claude plugin update illo`, or enable marketplace auto-update |\n| **Codex** | `codex plugin marketplace add tmchow/illo-skill` then `codex plugin add illo@illo-skill` | `codex plugin marketplace upgrade` |\n| **Grok CLI** | `grok plugin marketplace add tmchow/illo-skill` then `grok plugin install tmchow/illo-skill --trust` | `grok plugin update illo` |\n| **Grok Bot** | tap [the illo bot template](https://x.ai/bot/y3uTGY5hkl6iTmE-ZAX02) | add the template again after updates |\n| **Gemini CLI** | `gemini extensions install https://github.com/tmchow/illo-skill` | `gemini extensions update illo` |\n| **Copilot / GitHub CLI** | `gh skill install tmchow/illo-skill illo` (cross-agent via `--agent`) | `gh skill update illo` |\n| **Hermes** | `hermes skills install tmchow/illo-skill/illo` | `hermes skills update illo` |\n| **OpenClaw** | `openclaw skills install illo` | reinstall with the same command |\n| **Cursor** | `npx skills add tmchow/illo-skill --skill illo` (Cursor Marketplace listing pending review) | re-run the installer |\n| **Muse (Blip)** | Paste into your Muse chat: `Install the illo skill from https://github.com/tmchow/illo-skill` | Ask Muse to update the illo skill |\n| **Other agents / last resort** | `npx skills add tmchow/illo-skill --skill illo` | `npx skills update` |\n\n### Grok Bot\n\nOpen the [illo bot template](https://x.ai/bot/y3uTGY5hkl6iTmE-ZAX02) and tap **Add to Grok Bot**. That creates an illo bot on your account.\n\nFrom an interactive Hermes session:\n\n```text\n/skills install tmchow/illo-skill/illo\n/reload-skills\n/skill illo\n```\n\n> Use the directory identifier, not a raw `SKILL.md` URL — illo is a\n> multi-file skill (engine script, references, character sheet), and the\n> single-file URL form would install the instructions without the engine.\n\nReleases are tagged `v<version>` and the version in every native manifest is\nkept in lockstep with `SKILL.md` by Release Please and CI.\n\n## Use it for\n\n- **Article illustrations** — paste a post or doc; it finds the few\n  load-bearing moments (never one image per paragraph), proposes a shot list,\n  and produces a set you can interleave through the piece.\n- **A single concept** — \"illustrate *you are the bottleneck*\" → one deadpan\n  scene that lands one takeaway. If the idea is thin, it asks a couple of quick\n  questions first instead of guessing.\n- **Surprise / random** — \"surprise me\", \"random\", or scoped variants like\n  \"surprise me with art quote using bray\": rolls provenance (~1/3 verified\n  quote / topical hook / original; a `* quote` focus forces a cited quote),\n  builds three shareable saying candidates, then lets you pick (or\n  auto-picks the best with `--autopick` — preferred for schedulers), picks\n  register from the locked saying and a random installed character unless\n  named, and returns one image plus that caption-ready line. Built for casual\n  prompts and scheduled agents alike.\n- **Mini-comics** — a process, a before→after, a fail→fix told in 2–4 panels\n  inside one image. The best shape when a sequence belongs together — and for\n  social, where one self-contained image beats a thread.\n- **Explainer diagrams** — when the point *is* the structure (labeled\n  stages, a fan-out, a timeline, a loop, a layered stack), ask for \"the\n  flow\", \"as labeled stages\", \"label the steps\", \"walk the stages\", or\n  \"an explainer\" and the same mascot and look draw it as a hand-built\n  sketch-diagram: named phases, one flow direction, station names plus\n  arrow notes — traceable, but never a PowerPoint / Visio flowchart look.\n  Asking for a flowchart still means labeled stages in the pack's look.\n  A named pipeline or recipe is labeled stages: one connected system,\n  solved for that character, never a new look. The world is invented\n  from the thesis and the pack. The scene stays the default; the\n  diagram register is opt-in or earned by content whose thesis is the\n  structure itself.\n- **Character cutouts** — transparent PNG of the mascot alone (pose, optional\n  contact objects in touch with the body) for slides, compositing, or handing\n  off to another tool. Codex uses native alpha; the engine keeps chroma as an\n  automatic OpenRouter and explicit compatibility path. Not for explaining an\n  idea — that stays editorial.\n- **Your own mascot** — the character builder interviews you (or starts from\n  art you already have), pressure-tests the concept against the house\n  guardrails, renders model-sheet candidates, and installs the winner as a\n  named character pack in `~/.config/illo/characters/<name>/`. Keep several\n  packs, set a default in the config, and switch per run by name (\"use\n  blot\"). Every image stars the active character, kept on-model by a\n  reference lock.\n- **Community characters** — browse and install packs from\n  [illo-characters](https://github.com/tmchow/illo-characters) (\"install the\n  blip character\", or `packs install --all` to install the catalog locally);\n  installs are pinned, and \"update blip\" pulls the repo's\n  current version when you want it. Or publish your own: the skill opens a PR there with your\n  model sheet and a scene render embedded for one-glance review. Companies\n  can point `packsRepo` at a private pack repo instead.\n- **Blog / brand-matched art** — `~/.config/illo/palettes.md` holds your own\n  named palettes (the skill builds one for you by reading your site's CSS:\n  background → paper, text → ink, link color → accent) plus plain-text\n  destination lines like `blog → notes`. After that, blog posts wear your\n  site's colors and X posts wear the bold house palette — same character,\n  automatically. Or hand it one brand color and it derives a full palette\n  around it.\n- **Social-ready art** — bold house palette, square or wide, with your handle\n  hand-lettered in as an optional watermark (from your config; never a built-in\n  default).\n- **Choosing between options** — render variations or run the same prompt\n  across multiple models, then get a **self-contained comparison gallery**\n  showing each image's model, cost, and prompt.\n\nThroughout, the mascot stays on-model via a **reference lock**, every image is\nself-checked against a quality bar (one idea per image, accent restraint, no\nstray titles, fresh metaphor every time), and aspect ratios cover article\n(16:9), social (1:1), and vertical formats.\n\n## Notes\n\n- This style is intentionally **not** photorealism, logos, UI mockups, charts,\n  or generic stock art.\n- Image models approximate exact colors; the skill eyedrops and re-rolls\n  off-target palettes.\n\n## In this repo\n\nThe skill lives in this directory (`skills/illo/`). Installers copy it\nverbatim, so only what every install should ship belongs here. Docs-only\nimages live in [`_assets/illo/`](../../_assets/illo/) at the repo root\n(linked by raw URL). Proven explainer renders used on the repo README are in\n[`docs/examples/`](../../docs/examples/). Plugin manifests sit at the repo\nroot (`.claude-plugin/`, `.codex-plugin/`, `.cursor-plugin/`,\n`.grok-plugin/`, `gemini-extension.json`).\n\n## License & credit\n\nMIT © Trevin Chow. Illo — including the **Blot** default character and the\nbundled example artwork — is original work; if you redistribute or build on\nit, please keep attribution. See [`NOTICE`](NOTICE). Characters you create\nwith the character builder are, of course, yours.\n\n---\n\n`SKILL.md` is the agent-facing instructions — you don't need to read it to use\nthe skill.\n\nFile v0.37.0:_meta.json\n\n{\n  \"ownerId\": \"kn7ey3j7hw5sw95h24y5scayc57zz8rf\",\n  \"slug\": \"illo\",\n  \"version\": \"0.37.0\",\n  \"publishedAt\": 1790022053020\n}\n\nFile v0.37.0:references/article-set-character-reroute.md\n\n# Article-set character reroute\n\nUse this gate when an article/newsletter set is being rerouted to a different\ncharacter after a weak or failed attempt, or whenever a new mascot/domain world\nis introduced for a technical or platform essay. The expensive failure mode is\nnot bad drawing; it is a handsome set whose private metaphor system no longer\nmaps to the article.\n\n## Mandatory legibility preflight\n\nBefore spending any renders, write a preflight row for every proposed shot:\n\n- **Section claim** — the section-level thesis this image must land, in plain\n  article language.\n- **Visual object/action** — the one object and mascot action that will be\n  visible in the frame.\n- **Reader mapping** — how a reader gets from that object/action back to the\n  section claim without seeing your notes.\n\nReject or rewrite the shot if the mapping needs either of these:\n\n- a private metaphor glossary (\"in this world, the cactus means infra debt\");\n- more than one conceptual substitution before the claim becomes clear.\n\nOne clean metaphor is allowed and often good. The test is whether the reader can\nname it from the scene, not whether it is literal.\n\n## Technical / platform essays\n\nFor technical, infrastructure, SaaS, protocol, or platform pieces, default the\ncore scene to native article primitives the reader already knows: accounts,\npermissions, meters, tokens, gates, ledgers, switches, apps, providers, queues,\nkeys, quotas, bills, routes. Let the character pack's domain world supply the\naccent, posture, and action — not the entire conceptual system.\n\nGood reroute shape: the mascot pushes a permission gate, carries a token across\na provider switch, patches a leaky meter, or reconciles a ledger. Risky reroute\nshape: every concept becomes a character-world object that must be decoded\nbefore the article's claim can be read.\n\nThis is not a license to flatten the work into stock SaaS diagrams. Keep the\nillo house style: one fresh physical move, one invented built object, quiet\nspace, and a load-bearing mascot. Avoid generic dashboards, formal charts,\nUI mockups, and literal office art.\n\n## Hero before style anchor\n\nIn a hero + set, the rerouted hero may become the style anchor only after it\npasses both gates:\n\n1. **Visual quality** — normal quality bar: on-model mascot, palette, restraint,\n   composition, no artifact/title failures.\n2. **Thesis legibility** — a reader can connect the scene to the piece's central\n   claim without a private glossary or a chain of substitutions.\n\nA visually strong but illegible hero is not a safe second reference; it will\npropagate the wrong metaphor into the whole set.\n\n## Explainer mode and labels\n\nExplainer register is valid for multi-image article sets when a section needs a\ntraceable structure. Technical sections often become more legible as labeled\nstages, flow, fan-out, timeline, loop, stack, or system slice than as a pure\neditorial scene.\nKeep it hand-built and character-led, not a formal flowchart.\n\nLabels and titles are not forbidden, but image models are unreliable with text.\nFor editorial article placement, prefer no baked-in titles; the prose and\ncaption can do that work. When an explainer needs labels, keep them short,\nparallel, and placed on bare ground. If the final depends on exact words, prefer\nadding labels deterministically after generation or in post-process instead of\ntrusting the image model prompt.\n\n## Do-not-overcorrect checks\n\nBefore rendering the revised set, confirm all of these are true:\n\n- The mascot is still load-bearing: remove it and the action/claim collapses.\n- The set has not become a literal stock diagram or corporate infographic.\n- At least one clean metaphor or editorial invention remains where it helps the\n  piece feel memorable.\n- Each shot has only one main substitution between object/action and claim.\n- Labels are few, short, and optional unless the section truly needs traceable\n  structure.\n\nFile v0.37.0:references/backends.md\n\n# Backends and transports\n\nillo has **three engine backends** plus one named **agent-side transport**. All\nproduce the same kind of file; they differ in where the image is made, how the\nagent reaches it, and who is billed.\n\n- **Codex** — drives the user's already-installed, already-logged-in **Codex\n  CLI** (`codex exec`) to reach its built-in `image_generation` tool\n  (gpt-image-2). Free for Codex subscribers (no per-image charge); it draws\n  on the user's Codex usage quota.\n- **Grok CLI** — drives the user's **Grok (xAI) CLI** (`grok -p`, its headless\n  single-turn mode) to reach its built-in `image_gen`/`image_edit` tools. Free\n  for Grok subscribers; draws on the user's Grok usage quota. Same env-free,\n  token-free subprocess design as Codex. **Cannot produce transparent cutouts**\n  (Grok returns JPEG with no alpha) — cutout renders redirect to a\n  cutout-capable backend.\n- **Grok Bot native** — when the agent is **Grok Bot** (Cursor's Grok Bot /\n  the Grok desktop assistant), the agent persists `backend: grok-bot` with\n  `init --backend grok-bot --no-key`, then calls Grok Bot's built-in Grok image\n  tool directly with illo's prompt and reference image. This is the same Grok\n  image-model class as the CLI backend, but a different harness: no Grok CLI and\n  no OpenRouter key. It is not a generic \"any host image API\" escape hatch.\n- **OpenRouter** — calls OpenRouter's image API directly. Pay-per-image\n  through the user's OpenRouter account. The direct paid backend and the only\n  engine backend a host without a subscription CLI can use. A failed CLI render\n  reaches it only when `--allow-paid-fallback` is explicitly supplied;\n  intentional cutout routing is unchanged.\n\n`--backend` (and config `backend:`) selects an engine backend or the explicit\nagent-side `grok-bot` transport; otherwise the engine resolves the right engine\nbackend by host capability. Resolution and readiness are reported by `doctor`.\n`illo.py generate` refuses `grok-bot` because only the Grok Bot agent can call\nits native image tool.\n\n## Engine resolution and default (capability-aware)\n\nThe backend is resolved per run, never a static flip:\n\n```\n--backend  >  config backend:  >  capability-aware engine default\n```\n\nThe **capability-aware engine default** is, in order:\n\n1. a **usable Codex CLI** is present → `codex`;\n2. else a **usable Grok CLI** is present → `grok`;\n3. else an **OpenRouter key** is configured → `openrouter`;\n4. else none → onboarding (the engine names the fixes).\n\nThis never silently breaks an existing OpenRouter-only install on upgrade: a\nhost with a key but no subscription CLI still resolves to `openrouter`, so\n`doctor` stays exit 0. `grok-bot` is never auto-detected; the Grok Bot agent\nself-identifies by running `init --backend grok-bot --no-key`. An explicit\n`--backend`/`backend:` choice is honored as-is; readiness is judged separately,\nso `doctor` can flag a chosen-but-unusable backend or green-light `grok-bot`.\n\n### The self-identify rule (agent-driven, not engine-driven)\n\nThe precedence above reads **host** capability — the engine can't tell which\nagent invoked it, so on a host with both Codex and Grok usable it defaults to\nCodex. But the **agent** knows which agent it is. So the actionable rule lives\nin `SKILL.md`:\n\n- A subscription-CLI agent whose own CLI is usable here adds its own\n  `--backend` flag for non-cutout renders (the **Grok CLI agent** →\n  `--backend grok`, the **Codex agent** → `--backend codex`). That keeps\n  \"running in Grok, generate with Grok\" true even when Codex is also installed.\n- **Grok Bot** persists `backend: grok-bot` with\n  `init --backend grok-bot --no-key` when backend is unset/auto. It does not\n  call `illo.py generate`; it builds the same illo prompt and calls Grok Bot's\n  built-in Grok image tool with the active character sheet as a reference.\n\nBoth rules avoid engine runtime sniffing (no process-tree guessing, no reading\na secret-shaped `GROK_AUTH*`/`*_TOKEN` env var — both of which the skill's\nscanner-safe posture forbids). A user's explicit config `backend:` still\noverrides everything; cutouts ignore Grok paths and redirect off Grok\nregardless.\n\n### Migration: existing configs choose once for engine generation\n\nThe config carries a `configVersion` stamp (current: `2`, the version that\nintroduced the backend choice). A config written by an **older install** lacks\nit — that user has never been offered a subscription CLI vs OpenRouter, and\nsilently picking one (flipping them to a CLI, or quietly keeping OpenRouter so\nthey never learn the CLI backends exist) is the wrong call. So an out-of-date\nconfig is **not auto-resolved**:\n\n- `generate` **hard-stops** with a message to choose a backend (an agent reusing\n  an old playbook learns its config is stale rather than rendering on a guess).\n- `doctor` reports `backend: NEEDS CHOICE` and exits non-zero.\n\nThe choice is surfaced **interactively** (the agent asks Codex vs Grok CLI vs\nGrok Bot vs OpenRouter; see SKILL.md \"Config migration\") and persisted with\n`init --backend <codex|grok|grok-bot|openrouter> --no-key`, which stamps\n`configVersion` and keeps any existing key. A brand-new install (no config) is\nordinary onboarding, not a migration — it resolves capability-aware as above,\nexcept Grok Bot agents self-identify by writing `backend: grok-bot`. The stamp,\nnot the `backend` key's absence, is the signal: a current-version user who chose\n\"auto\" also has no `backend` key but is not re-prompted.\n\n## Codex backend\n\n### The Codex-CLI requirement (detection)\n\nEligibility is a property of the **execution host**, detected — never\nassumed. A Claude Code, Cursor, Gemini, Hermes, or OpenClaw run on a\nCLI-equipped host all qualify equally; a Codex-harness run on a bare host\ndoes not. The host is \"usable Codex\" only when **all three** hold:\n\n1. `codex` is on `PATH`;\n2. `codex login status` reports logged in;\n3. `codex features list` reports the `image_generation` row. Codex 0.144 folded\n   generated-image artifact handling into this stable feature, so its presence is\n   the whole capability signal. (Codex 0.141 also required an experimental\n   `imagegenext` extension to make `codex exec` emit the artifact; that extension\n   was removed once the behavior went stable, so illo no longer gates on it.)\n\nAny non-zero detection exit, timeout, or unparseable output means Codex is not\nusable. The capability-aware default can then select Grok or direct OpenRouter.\nOnce Codex is selected for a render, generation fails closed by default;\nOpenRouter retry requires `--allow-paid-fallback`. Detection runs once per\nprocess and reads **no** credential file and **no** secret-shaped env var.\n`doctor` reports the stage that failed (`codex login` needed, feature\nunavailable, etc.).\n\nIf the user needs to enable it: install the official Codex CLI and run\n`codex login` — that is the entire setup. illo never touches the token.\n\n### gpt-image-2 is automatic — no model selection\n\nThe free built-in tool exposes **no model selector**; it renders with\nCodex's current default, **gpt-image-2**. So on the Codex backend the\n`--model` flag and config `model:` **do not apply** — they are an\nOpenRouter-only axis. (Pinning a model would require the *billed*\n`image_gen.py --model` CLI, which needs an API key and defeats \"free for\nsubscribers\" — out of scope.)\n\nAspect has no size argument on the free tool either; illo states the aspect\nin the prompt text, which gpt-image-2 honors. As always, check\n`.width/.height` in the JSON line and re-roll a stray wrong-dimension result.\n\n### Native-alpha cutouts\n\nFor `--cutout`, illo appends a native transparent-PNG contract to the Codex\nprompt and preserves clean alpha from gpt-image-2. An explicit `--chroma`\nforces the older compatibility screen and post-process instead. Do not put a\nmanual `BACKGROUND:` or output-format block in the prompt; backend routing owns\nthat contract. Read `cutout_alpha`, `cutout_method`, and `cutout_note` after\nevery render because native alpha can still carry a model-drawn edge halo.\n\n### Quota, not a per-image charge\n\n\"Free\" means there is no per-image dollar charge — it **draws on the user's\nCodex usage quota**, and image turns consume that allowance faster than text\nturns. The questionnaire (run by the user during `init`) states this before\nenabling Codex.\n\n### Transport and character lock\n\nillo invokes `codex exec` against the built-in tool, attaching the active\ncharacter's reference sheet (`-i <sheet>`) so the mascot stays on-model, and\nasks the agent to save the result to the run-dir path. As of Codex CLI 0.144\nthe stable `image_generation` feature drops the generated artifact under\n`$CODEX_HOME/generated_images/<session-id>/<image>.png` on its own — illo\nverifies the requested path first and otherwise fetches the freshest valid image\nartifact at that fixed depth that postdates the exec. (On Codex 0.141 this\nrequired an extra `--enable imagegenext` flag, since\nthe stable feature did not emit the artifact reliably; the extension was removed\nonce the behavior went stable, so illo no longer passes the flag.) Artifact\npresence takes precedence over wrapper status: Codex can complete\n`image_generation` and persist the PNG, then exit 1 because its final assistant\ntext is empty. A valid requested or fresh generated artifact is still a Codex\nsuccess, including after a timeout; only a run with no valid fresh artifact\nfails.\n\nWith no `--ref` and no\ndefault character there is nothing to lock to, so illo renders ref-less (a\none-line note marks it) — matching OpenRouter, and exactly what bootstrapping a\nbrand-new character's first model sheet needs (`references/character-builder.md`\nstep 4). illo handles **no token**: it runs no OAuth, reads no\n`~/.codex/auth.json`, hits no endpoint —\nthe only privileged action is the subprocess call to the user's own CLI\n(the one sanctioned exception to the stdlib-over-subprocess rule — a benign\ncall to a known CLI, not a credential read). The adapter verifies the file\nlanded, otherwise fetches the\nfreshest image the tool dropped under\n`$CODEX_HOME/generated_images/<session-id>/`\n(`$CODEX_HOME` resolved at run time — relocatable, never hardcoded).\n\n### Windows/WSL is unsupported\n\n`codex exec` image generation is broken on Windows/WSL (openai/codex#19133).\nillo treats that as a backend failure. Select OpenRouter directly, or explicitly\npermit the paid retry with `--allow-paid-fallback` when a key is configured.\n\n### Fallback behavior\n\nWhen the Codex backend is unavailable or produces no valid fresh artifact, illo\n**fails closed by default**, even when an OpenRouter key is configured. It falls\nback to OpenRouter only when the caller explicitly supplies\n`--allow-paid-fallback`; that paid record is tagged `backend: openrouter`.\nDirect `--backend openrouter` generation is not a fallback and does not need the\nflag.\n\nA Codex-served record carries `cost: null` and no model id, and the engine\nnever queries OpenRouter for its cost. When an explicitly authorized Codex\nfallback lands on OpenRouter, illo replaces its native-alpha contract with the\npack's chroma compatibility screen and records that actual prompt.\n\n## Grok Bot native transport\n\nGrok Bot native is an **agent-side transport**, not an engine backend. Use it\nonly when the agent is **Grok Bot**: Cursor's Grok Bot / the Grok desktop\nassistant with a built-in Grok image generation tool. Other agents that happen\nto expose some image API must not take this path; they use Codex, Grok CLI, or\nOpenRouter through the engine.\n\n### Routing and readiness\n\nRun `doctor` first for the non-transport checks: Python can launch the engine,\nthe skill path is correct, bundled assets are intact, custom packs are readable,\nand palette/config files parse. On first Grok Bot preflight when backend is\nunset/auto, run `init --backend grok-bot --no-key`, then run `doctor`.\nWith `backend: grok-bot`, missing Codex CLI, Grok CLI, and OpenRouter key are\nexpected; `doctor` exits 0 when the non-transport checks pass.\n\nAn explicit user/backend choice still wins. If config or the request says\n`backend: openrouter`, `backend: codex`, or `backend: grok`, honor that engine\nbackend and handle its readiness/failure normally instead of silently switching\nto Grok Bot native.\n\n### Tool use and model behavior\n\nBuild the prompt exactly as `references/prompt-recipe.md` specifies, including\nthe active character spec, style file, palette mapping, composition register,\ntext budget, and QA constraints. Attach the active character's model sheet as a\nreference image (`assets/character-reference.webp` for Blot, or the pack's\n`reference.png`); for image sets, attach the accepted style anchor as a second\nreference on later images. Ask Grok Bot's built-in Grok image tool for the\ntarget aspect ratio and saved output file.\n\nThis is the same Grok image-model class as the Grok CLI backend: no model\nselector, no OpenRouter billing, and no alpha channel. The returned/saved file\npath is the `.path` equivalent for QA and delivery. `illo.py generate` refuses\n`grok-bot` with a message to use the agent-side tool; there is no manifest\nrecord from the engine unless a separate engine render is run.\n\n### No transparent cutouts\n\nGrok Bot's native image tool returns opaque Grok images, like the Grok CLI path.\nDo not use it for transparent cutouts. Route cutouts to a cutout-capable engine\nbackend (Codex if usable, otherwise OpenRouter GPT Image 2 when configured) or\nstop and ask for that backend to be configured.\n\n## Muse native transport\n\nMuse native is an **agent-side transport**, not an engine backend. Use it\nonly when the agent is **Blip**: Meta's personal assistant (Muse) with a\nbuilt-in image-generation tool. Other agents that happen to expose some image\nAPI must not take this path; they use Codex, Grok CLI, or OpenRouter through\nthe engine.\n\n### Routing and readiness\n\nRun `doctor` first for the non-transport checks: Python can launch the engine,\nthe skill path is correct, bundled assets are intact, custom packs are readable,\nand palette/config files parse. On first Muse preflight when backend is\nunset/auto, run `init --backend muse-native --no-key`, then run `doctor`.\nWith `backend: muse-native`, missing Codex CLI, Grok CLI, and OpenRouter key are\nexpected; `doctor` exits 0 when the non-transport checks pass.\n\nAn explicit user/backend choice still wins. If config or the request says\n`backend: openrouter`, `backend: codex`, or `backend: grok`, honor that engine\nbackend and handle its readiness/failure normally instead of silently switching\nto Muse native.\n\n### Tool use and model behavior\n\nBuild the prompt exactly as `references/prompt-recipe.md` specifies, including\nthe active character spec, style file, palette mapping, composition register,\ntext budget, and QA constraints. Attach the active character's model sheet as a\nreference image (`assets/character-reference.webp` for Blot, or the pack's\n`reference.png`); for image sets, attach the accepted style anchor as a second\nreference on later images. Ask the native image tool for the target aspect\nratio and saved output file. Up to four native image calls may be batched in\none response; beyond that, continue in a follow-up.\n\nThere is no model selector and no OpenRouter billing on this path; `--model`\ndoes not apply. The native tool returns opaque images (no alpha channel), so\ncutouts go through the chroma compatibility path below. `illo.py generate`\nrefuses `muse-native` with a message to use the agent-side tool. Record every\nnative render with `illo.py record` so it joins the run's `manifest.jsonl`\n(and galleries) like an engine render.\n\n### Cutouts via chroma + keyout\n\nThe native tool cannot emit transparency directly, but it holds a flat chroma\nscreen well enough to key out: ask for the pack's declared chroma (green or\nmagenta), save the screen render, then run\n`illo.py keyout <screen.png> --chroma <green|magenta> --out <final.png>`,\nwhich keys and despills through illo's existing chroma path and appends a\n`muse-native` manifest record. Full procedure, QA, and the opaque-fallback\nrule: `references/cutout.md`.\n\n## Grok CLI backend\n\nThe Grok CLI backend is the Codex backend's twin: it drives the user's own Grok\nCLI to reach a built-in image tool, handling no token itself.\n\n### Detection\n\nThe host is \"usable Grok\" when **both** hold:\n\n1. `grok` is on `PATH`;\n2. a login credential is present — the credential file (`$GROK_HOME/auth.json`,\n   `$GROK_HOME` default `~/.grok`) **exists**.\n\nDetection reads the credential file's **existence only, never its contents**\n(scanner-clean: no secret read, no secret-shaped env var — `$GROK_HOME` is a\npath, not a secret). The image tools' reachability can't be probed without a\nbilled call, so a logged-out or image-ineligible account fails at generation\ntime rather than detection. The capability-aware default can choose the next\navailable backend when Grok CLI is not detectable; once a Grok CLI render\nstarts, paid OpenRouter retry is opt-in. Detection runs once per process.\n`doctor` reports whether the CLI is usable, present-but-logged-out, or absent.\nSetup is the entire story: install the Grok CLI and run `grok login`.\n\n### The image tool is automatic — no model selection\n\n`grok -p` fires Grok's built-in `image_gen`/`image_edit` tools; the image model\nis not the chat model and exposes no selector, so **`--model` and config\n`model:` do not apply on the Grok CLI backend** (an OpenRouter-only axis, exactly\nlike Codex). Aspect is honored: illo states it in the prompt and Grok's tool\nmaps it (`1:1`, `16:9`, and non-enum ratios like `3:2` render at the right\ndimensions). As always, check `.width/.height` and re-roll a stray result.\n\n### No transparent cutouts (JPEG, no alpha)\n\nThe Grok CLI image tool returns **JPEG with no alpha channel**, and its \"solid\nbackground\" renders come back as gradients with the subject drifting toward the\nkey color — so chroma-keying fails (opaque corners, heavy fringe). illo does\n**not** attempt cutouts on Grok: a `--cutout` render whose backend resolves to\n`grok` **redirects** to a cutout-capable backend — Codex if usable, else\nOpenRouter GPT Image 2 if a key is set — and prints a note; with neither it\nexits naming both fixes. This pre-render capability redirect is intentional and\ndoes not require `--allow-paid-fallback`. The manifest records the backend that\nactually ran.\n\n### Quota, transport, and character lock\n\n\"Free\" means no per-image dollar charge — it **draws on the user's Grok usage\nquota**, faster for image turns than text. The `init` questionnaire states this\nbefore enabling Grok. illo invokes `grok -p` with `--always-approve --cwd\n<run-dir>`, instructing the agent to fire the image tool (not construct the\nimage in code) and save to the run-dir path; with a reference sheet it steers\n`image_edit` (reference read by filesystem path — Grok has no `-i` flag) for\ncharacter lock, else `image_gen` for a ref-less bootstrap render. It handles\n**no token**: no OAuth, no read of `~/.grok/auth.json`, no endpoint — the only\nprivileged action is the subprocess to the user's own CLI (the same sanctioned\nexception to the stdlib-over-subprocess rule as Codex). The adapter verifies the\nfile landed, else fetches the freshest image the tool dropped under\n`$GROK_HOME/sessions/**/images/`.\n\n### Fallback behavior\n\nWhen the Grok CLI backend is unavailable or produces no retrievable image, illo\n**fails closed by default**, even with a configured OpenRouter key. It retries\nthrough OpenRouter only when `--allow-paid-fallback` is explicitly supplied\n(record tagged `backend: openrouter`). A Grok-served record carries `cost: null`\nand no model id.\n\n## OpenRouter backend\n\nThe pay-per-image path, billed to the user's OpenRouter account. It is\n**model-selectable** (`--model`; see `references/models.md` for the lineup,\nthe friendly-name → id map, the aspect caveat, and 404/fallback handling).\nUse it directly with `--backend openrouter` without any fallback flag. It is also\nthe capability-aware default on a host with a configured key and no usable\nsubscription CLI, the explicit paid retry target after a failed CLI render, and\nthe intentional redirect target for Grok cutouts. Its wire behavior is unchanged\nfrom a single-backend install.\n\nFile v0.37.0:references/character-builder.md\n\n# Character builder\n\nDesign a user's own recurring mascot and install it as the active character\npack. Read `references/character.md` first — the guardrails there are the\nacceptance criteria for everything below. The whole flow costs a few paid\nrenders (typically under ten cents each); say the projected cost before\ngenerating.\n\n## 1. Interview (one short round, ≤4 questions)\n\nAsk only what changes the design:\n\n- **What is it?** An object or creature from the user's domain, product, or\n  brand (a teapot, a terminal cursor, a fox). Push toward things with one\n  simple silhouette.\n- **What look?** The pack's one style: riso (house default) or another from\n  the look library — blueprint, woodcut, pixel, clay, manila, chalk,\n  phosphor, enamel, gouache, felt, diorama, sketchbook, bricks, fizz, bloom, snes — or a custom style file. The model sheet and\n  every scene render in this style.\n- **Where is the accent?** One small part that will carry the palette accent\n  in every image (a tip, a fold, a tail, a topknot).\n- **A name?** Optional — the best names read off the design. Offer one if the\n  user doesn't have one. If the chosen name *doesn't* read off the subject\n  (an ox named `yoke`), ask for **aliases** — the words people would summon\n  it by (\"ox\", \"zebu\") — and record them in the spec's `Aliases:` line so\n  \"use ox\" resolves to the pack.\n- **Any must/never elements?** (e.g. \"no corporate logo shapes\").\n\nSkip questions already answered by context. If the user **already has art** —\nan existing mascot drawing, logo, or sketch — use it: pass it as `--ref` in\nstep 4 so the candidates stay close to the original while the prompt\ntranslates it into the house line language.\n\n**The face is deliberately not an interview question.** The house face — two\ndot eyes, blank deadpan, no mouth, no brows — is the catalog's family look\nand the most render-stable choice: apply it by default without asking. But\nit is a default, not a rule. If the user asks for something else (a mouth,\nbrows, a different body plan, a body built from a material), accommodate\nthem — `character.md`'s locked-face and locked-treatment rules say how:\nexact render-checkable terms, never moods — and say the trade-offs out loud:\nmore facial detail means more drift and harder QA, and designs that diverge\nfrom the house family face a higher review bar if published to the\ncommunity catalog.\n\n## 2. Pressure-test the concept before rendering\n\nWork through the anti-complexity guardrails in `character.md` one by one and\npush back early:\n\n- A concept that needs text or many distinctive parts to read as itself will\n  drift off-model across renders — simplify it or pick a different object.\n  Accessories (a hat, a tool, a pattern) are allowed but each must be locked\n  in the spec and survive every render; every part is a drift liability.\n- A face beyond the deadpan default must be specified in render-checkable\n  terms — exact shapes, not moods. \"Smiling warmly\" drifts; \"a thin flat\n  structure-ink mouth\" locks.\n- Can it physically perform a move? Walk the interaction-model fields\n  (`character.md`) against one sample action — what touches, what supports,\n  how far it reaches. A character with no workable contact surface can't be\n  load-bearing; fix the design now, not per-image.\n- Does the silhouette stay readable at thumbnail size?\n- Is it distinct from a visual cliché the reader already knows (a generic\n  file icon, an emoji, a famous mascot)? Collisions read as borrowed IP.\n\nRewrite the concept with the user until it passes; this step saves more\nrenders than any prompt tweak.\n\n## 3. Draft the locked spec\n\nFill this template (it becomes `character.md` in the pack):\n\n```markdown\n# {Name} — custom character\n\n{One sentence: what it is, and why the name reads off the design.}\n\nStyle: **{look name — riso if unset}**\nAliases: {subject + synonyms, comma-separated — omit this line if the name already reads off the subject}\n\n## Locked design\n\n- **Body**: {the one silhouette, in concrete geometric language}.\n- **Face**: {the locked face — house default: two simple dot eyes, blank\n  deadpan, no eyebrows, no mouth}.\n- **Accent carrier**: {the one accent part} — the only accent-colored part.\n- {limbs — house default: small stubby arms and legs}.\n\n## Interaction model\n\n- Contact surfaces: {parts that may touch/operate objects, and how — e.g.\n  \"rounded arm tips: press and carry only, no grasp\"}.\n- Reach: {fixed | stubby | short | normal | long | articulated | body-contact only}.\n- Grip: {none | pressure/contact only | hook | pinch | grasp}.\n- Support/locomotion: {feet | paws | wheels | base | body mass | flight}.\n- Protected regions: {e.g. the face interior — only the locked marks appear there}.\n- Special operators: {a tail, horn, handle, or mouth that may operate\n  objects — omit the line if none}.\n\n## Prompt spec (drop into the CHARACTER slot)\n\n> the recurring mascot — {body description}, {the locked face spec},\n> {limbs}; the ONLY accent-colored part is {the accent part}. It MUST\n> perform the move, not decorate. {value rule, from the next section}\n\n## Value rules\n\n- **Dark/bold palettes**: {how the body reads — dark fill or light with ink\n  outline; what color the eyes are}.\n- **Light palettes**: {how the body reads — per the value-follows-palette\n  rule in character.md}.\n\n## Personality\n\n{Default: an earnest, low-key operator doing something slightly absurd with a\nstraight face. Adjust freely — keep it consistent with the locked face, and\nlet the move, not the expression, carry the idea. Lead with what the character\n*is and does*; if you name a use-case, keep any engineering use as one lens at\nthe end, never the headline — the catalog is a cast of mascots, not a devops\nicon set.}\n```\n\n### Optional cutout chroma compatibility\n\nCodex cutouts use native alpha by default, so a new pack needs no chroma\ndecision. The fallback/OpenRouter path keys a flat screen color to alpha in\npost and defaults to magenta. Add **`Cutout chroma: green`** only when the\ndesign needs a different compatibility screen.\n\n1. Collect every hex in the palette (structure, accent, fills).\n2. Omit the line for the **magenta** default.\n3. Add **`Cutout chroma: green`** only when the character is forged/wrought\n   metal (e.g. Wick) or the optional compatibility proof below shows persistent\n   magenta fringe on fine edges.\n4. Either screen color must stay **absent from the character palette** — never\n   use `#FF00FF` or `#00FF00` on the mascot itself.\n\n## 4. Generate model-sheet candidates\n\nRender each concept as a clean reference sheet — no scene, no labels. Use the\nprompt template below per concept, `--count 2`, aspect `1:1`, into a fresh\n`newrun` dir; build a `gallery` and let the user pick (or iterate). No `--ref`\non the first round — there is nothing to lock to yet (all backends/transports\nrender this first sheet ref-less; once it exists, every later scene render\npasses it as `--ref`).\n\n```text\nA 1:1 square character reference sheet (model sheet) for a recurring\neditorial mascot, on a plain empty paper background — no scene, no props, no\nlabels, no text anywhere.\n\nCHARACTER — \"{name}\", {what it is}: {the prompt spec paragraph from step 3}.\nCuteness comes from proportion and roundness only — no parts, accessories,\nor face details beyond the locked spec.\n\nPOSE: one large clean front-facing full-body view, centered, occupying about\n60% of the frame, standing neutral, limbs relaxed.\n\nLINE LANGUAGE: ONE bold, even-weight, softly-rounded outline (a clean\nvinyl-sticker line), nothing thin or scratchy.\n\nSTYLE: risograph print — grainy halftone texture, slight ink-layer offset,\nfaint paper grain, flat fills, no gradients, no soft shadows.\n\nPALETTE: paper warm white #fffef7. Structure ink near-black #111111. Accent\nfluoro pink #ff3d9a ONLY on {the accent part}.\n```\n\n(Use the user's own palette hexes instead if they already have one — the\nreference conditions the character's *shape*; palette stays per-image. For a\nnon-riso look, substitute the style file's LINE LANGUAGE and STYLE blocks and\nits classic-default palette into the template above — the sheet must be born\nin the pack's style.)\n\nQA each candidate against the guardrails in `character.md`: the locked face\nexactly (house default: deadpan, no mouth/brows), no unlocked parts, locked\ntreatments read in aggregate, one accent part only, silhouette reads at small\nsize. Reject before showing, and tell the user why a concept was re-rolled.\nIterate at most ~2 rounds; if a concept keeps drifting, that is the concept's\nfault — return to step 2.\n\n## 5. Install the pack\n\nPick a pack name — usually the character's name, lowercase kebab-case.\n**Names are globally unique** (they're how agents select characters): check\nthe community registry with `packs list` before settling, even if the user\nisn't publishing, and avoid the reserved names `blot`, `illo`, and the look\nnames (`riso`, `blueprint`, `woodcut`, `pixel`, `clay`, `manila`, `chalk`,\n`phosphor`, `enamel`, `gouache`, `felt`, `diorama`, `sketchbook`, `bricks`, `fizz`, `bloom`, `snes`). With a winner chosen:\n\n```bash\nPACK=\"${XDG_CONFIG_HOME:-$HOME/.config}/illo/characters/<name>\"\nmkdir -p \"$PACK\"\ncp <chosen-render>.png \"$PACK/reference.png\"\n# write the filled step-3 template to \"$PACK/character.md\"\n```\n\nConfirm with `python3 \"$SKILL_DIR/scripts/illo.py\" doctor` — it lists the\npack. Then ask whether this should become the **default character**; if yes,\nset it (non-secret, so you may run it):\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" init --no-key --character <name>\n```\n\nPer-run selection (\"use <name>\") beats the default — SKILL.md step 2. Offer a\nquick proof render: one simple scene with the new mascot performing a move,\n**rendered with the pack's `reference.png` passed as `--ref`**, so the user\nsees it on-model in action. The locked sheet is the **single source of\ntruth**: derive the preview — and every later scene — by conditioning on it,\nnever from the bare prompt or a sketch/seed alone. A sheet and a scene\ngenerated independently drift into two *different* characters; only\n`--ref`-ing the sheet keeps them the same mascot (the same rule SKILL.md\nstep 5 states for generation — it applies to the very first preview too).\n\n### Chroma compatibility proof for shared packs\n\nRun this proof before publishing or otherwise sharing a pack, and when adding\na non-default green override or claiming verified OpenRouter/chroma\ncompatibility. A local pack used only with Codex-native cutouts may skip it.\nAfter `reference.png` is installed, read\n`references/cutout.md` in full and build one prompt from\n`references/prompt-recipe.md`, \"Cutout variant\" (not the editorial template).\nUse a neutral front-facing wave pose and the pack's style blocks with a\n**registration-locked silhouette** (SILHOUETTE block — no ink-layer offset).\nDo not add a `BACKGROUND:` line; force the candidate screen with `--chroma`.\n\n```bash\nSKILL_DIR=\"<path to this skill>\";\nPACK=\"${XDG_CONFIG_HOME:-$HOME/.config}/illo/characters/<name>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" generate --prompt-file /tmp/<name>-cutout-proof.txt --ref \"$PACK/reference.png\" --aspect 1:1 --cutout --chroma <green-or-magenta> --out /tmp/<name>-cutout-proof.png\n```\n\nRead the JSON line: **`cutout_alpha`** must be true; **`cutout_note`** must\nnot warn of foot crop, screen fringe, or accent halos (`references/quality-bar.md`,\ncutout section). When `cutout_alpha` is false or QA fails:\n\n1. Re-roll once with the other `--chroma` screen.\n2. If green passes and magenta does not, add **`Cutout chroma: green`** to\n   `$PACK/character.md` and re-run the forced proof.\n3. If both fail, fix the prompt (SILHOUETTE / STYLE / feet margin) before\n   changing chroma again.\n\nDo not publish, share, or claim chroma compatibility until this proof passes.\nA community pack with an explicit override mirrors it in `index.json` as\n`\"cutout_chroma\"` (see `references/pack-sharing.md`).\n\nPacks are folders: remove one to retire it, copy it to another machine to\ninstall the character there. If the user wants to share it with everyone,\noffer to publish it to the community repo — `references/pack-sharing.md`.\n\n## Style variants\n\nA character's look is part of its pack — the same character in a different\nstyle is a **sibling pack**, built deliberately, never a runtime restyle:\n\n1. Name it `<name>-<style>` (e.g. `blot-woodcut`). Identity is unchanged:\n   copy the locked spec and prompt spec verbatim; set the `Style:` line to\n   the new look. Copy an explicit **`Cutout chroma:`** compatibility override\n   only when the new palette still passes that forced-chroma proof.\n2. Regenerate the model sheet in the new style (step 4, substituting the\n   style file's blocks), passing the **original pack's** `reference.png` as\n   `--ref` so proportions carry over. Far looks fight the original sheet's\n   rendering (worst: pixel) — the style file's character treatment and\n   forcing language are mandatory; QA against the new style's deltas plus\n   the character guardrails, and re-roll until the sheet is fully in-style.\n3. Install (and optionally publish) it as its own pack with its own preview.\n\nOne look per pack keeps galleries one-image-per-character and makes every\ncross-style move a cared-for act instead of a casual transplant.\n\nFile v0.37.0:references/character.md\n\n# The character\n\nEvery Illo image stars one recurring mascot — the subject of every scene,\nnever decoration. The rules in the first half of this file apply to **any**\ncharacter (the shipped default or a custom one); the second half is the\nshipped default, **Blot**, and the custom-pack format that replaces it.\n\n## Rules for any character\n\n### Anti-complexity guardrails\n\nThe fastest way to ruin a recurring character is detail creep. A character is\na small set of **locked** choices, and nothing else:\n\n- **One simple silhouette** — one body shape that reads at any size (the\n  house default favors a single soft geometric form; cuteness comes from\n  proportion and roundness, never from added parts). Bipedal is the default,\n  not a rule — a quadruped or other body plan is fine if the outline stays\n  simple and the character can still perform a move. The locked silhouette\n  and body proportions are non-negotiable in every register: they stay\n  the pack sheet's. Dramatize scale in the world (a too-small door, a\n  tiny hatch, an oversized pile), never by stretching, squashing, or\n  flattening the body to fill architecture or the frame.\n- **A locked face** — the face is the pack author's choice, but it must be\n  **exactly specified** and identical in every render. The house default —\n  two dot eyes, blank deadpan, no eyebrows, no mouth — is the most\n  drift-resistant face there is; a mouth, brows, or another simple face is\n  fine when the locked design pins it down in render-checkable terms (\"a\n  thin flat structure-ink mouth\", not \"a friendly smile\"). Faces are where\n  renders drift first: every extra feature is a consistency cost.\n- **Simple limbs** — enough to perform a move (house default: small stubby\n  arms and legs, no hands or detail).\n- **ONE accent carrier** — a single small part that takes the palette's accent\n  color (a tip, a fold, an antenna ball). Everything else is structure ink or\n  paper. Unlike the face and limbs, this is **not a per-pack choice** — the\n  palette system and the accent-discipline QA check depend on exactly one.\n\n**Nothing unlocked appears.** Panels, seams, bolts, gauges, UI, text on the\nbody, hats, clothing, accessories, extra appendages — allowed only when the\nlocked design names them explicitly, and then they must appear in every\nrender. If a render adds a part the spec doesn't have, re-roll; if renders\nkeep dropping or mutating a locked part, the design has too many parts —\nsimplify. A concept that *needs* many parts or text to read as itself will\nnot survive generation.\n\nA body **material** (built from paperclips, bricks, yarn) is a *treatment*,\nnot a part: lock the material and how it reads (\"a donkey built of\ninterlocking oversized paperclips\"), then judge consistency **in aggregate**\n— every render must read as that material at a glance, but individual units\nmay shift run to run the way hatching does. Locked parts are checked\none-by-one; locked treatments are checked as a whole.\n\n### A style may own a richer profile\n\nThe guardrails above are the house defaults, tuned for the minimalist bundled\nlooks. A **style/look file may deliberately loosen them** for its medium, as\nlong as the structural invariants still hold: one readable silhouette, exactly\nONE focal accent, a load-bearing performance, and an exactly-locked,\nreproducible design. A layered-craft look like `felt`, for example, builds the\nbody from many stacked felt pieces in several colors and pins a fuller cute\nface (dot eyes + a small stitched mouth + cheeks) — the richness lives in a\n**locked layer treatment judged in aggregate** plus a **multi-color body with\none focal accent**, never in loose extra parts. When a pack's `Style:` names\nsuch a look, that look file's \"Character treatment\" section governs: read it,\nand judge the pack by the structural invariants plus the look's own QA deltas,\nnot by the house minimalism.\n\n### Value-follows-palette (critical)\n\nThe character is built with the same value logic as the rest of the scene, so\nit never becomes a foreign blob:\n\n- **Dark/bold palettes** (e.g. `ink-punch`): the body may read dark — its\n  darkest feature is the deepest value in the scene.\n- **Light/warm palettes**: the body is **light/cream with the structure-ink\n  outline** (built like the props), and any dark feature uses the **structure\n  ink, not pure black**.\n\nWhen in doubt in a light palette: light body, charcoal (not black) features.\n\n### The character must be load-bearing\n\nThe mascot performs the idea's one move — wedged in the neck, cranking the\npress, holding the gate, hauling the load. Quick check: mentally **paint the\ncharacter out of the sketch.** If the picture still explains itself, it was a\nsticker — rebuild the scene so the move can't happen without the character in\nit.\n\n### The interaction model (what the character can physically do)\n\nEvery character has an interaction model — the packs that declare one (an\noptional `## Interaction model` section in their spec) state it; for every\nother pack, derive it conservatively from the locked design before planning\nany move. Its fields:\n\n- **Contact surfaces** — which locked parts may touch or operate objects,\n  and how (a rounded arm tip presses and carries; a hand grasps).\n- **Reach** — fixed, stubby, short, normal, long, articulated, or\n  body-contact only. A stubby limb cannot make a cross-torso or\n  far-from-body contact.\n- **Grip** — none, pressure/contact only, hook, pinch, or grasp.\n- **Support / locomotion** — feet, paws, wheels, base, body mass, flight.\n- **Protected regions** — areas scene/prop/limb strokes must never enter\n  (most packs: the face interior).\n- **Special operators** — a tail, horn, handle, antenna, or mouth may\n  operate an object **only when the pack names it as a contact surface**;\n  undeclared parts are non-operational.\n\nDerivation is conservative, never generous: do not infer hands, fingers, or\njoints from a bare \"arms\" declaration; when capability is ambiguous, prefer\nbody-weight, pressing, carrying, leaning, and passive contact over invented\ndexterity. Human anatomy is not the default. This model is what the\nanatomy-action feasibility gate (`composition.md`) validates moves against,\nand what \"declared contact surface\" means everywhere in the prompt recipe\nand quality bar.\n\n### Personality\n\nThe house default: an earnest, low-key operator doing something slightly\nabsurd with a straight face — calm, deadpan, competent, never zany or\ncute-for-cute's-sake. A pack may define its own personality; whatever it is,\nkeep it consistent, and remember the idea is carried by the **move**, not the\nface — expression is seasoning, never the message.\n\n### Naming\n\nIn generation prompts, describe the character by its **design**, not its name —\nimage models render the description, not the proper noun. Use the name in\nhuman-facing copy, captions, and shot lists. A good name reads off the design\n(an ink drop is a *blot*).\n\nWhen a name *doesn't* read literally off the subject (an ox named `yoke`, a\nmole named `mole` is fine but a robot named `blip` is not), give the pack an\noptional **`Aliases:` line** so users can summon it by what it is — \"use ox\"\n→ `yoke`. List the subject and common synonyms, comma-separated:\n\n```markdown\nAliases: ox, zebu, oxen\n```\n\nAliases are selection keys like the name, so the same global-uniqueness rule\napplies: an alias must not collide with another pack's name or alias, the\nshipped `blot`, or any look name. Absent line = name-only selection (the\nagent can still match on the subject prose, just less reliably).\n\n## Blot — the shipped default\n\n**Blot** is the default mascot: a small ink drop. Style: riso. The model sheet\nis `assets/character-reference.webp` — the engine conditions on it (see\nSKILL.md). (`assets/character-reference-pixel.png` is the sheet behind the\npixel look's calibration example — a ready-made base for a `blot-pixel`\nvariant pack.)\n\nCutout chroma: **magenta**\n\n### Locked design\n\n- **Body**: a plump rounded ink-droplet — a fat, soft teardrop, wide at the\n  bottom, narrowing to a gently curved tip at the top.\n- **Face**: two simple dot eyes directly on the body, blank deadpan.\n- **Accent carrier**: the **droplet tip** — the only accent-colored part.\n- Small stubby arms and legs.\n\n### Blot's interaction model\n\n- Contact surfaces: the rounded arm tips (press, push, pat, carry — no\n  fingers, no grasp) and the feet (stand, press a pedal, brace).\n- Reach: stubby — contacts stay close beside or below the body, never\n  across the torso or far from it.\n- Grip: pressure/contact only; Blot hugs or balances a carried object.\n- Support/locomotion: the two stubby legs.\n- Protected regions: the face interior — only the two dot eyes appear there.\n- Special operators: none; the accent tip is not a limb.\n\n### Blot's value rule\n\n- **Dark/bold palettes**: the body is filled solid with the structure ink (a\n  literal drop of ink); the eyes are paper/warm-white dots.\n- **Light palettes**: the body is light/cream with the structure-ink outline;\n  the eyes are structure-ink dots. The accent tip stays accent in both.\n\n### Prompt spec (drop into the CHARACTER slot of the recipe)\n\n> the recurring mascot — a plump rounded ink-droplet body (a fat soft\n> teardrop, wide at the bottom, narrowing to a gently curved tip at the top),\n> two simple dot eyes, blank deadpan (no eyebrows, no mouth), small stubby\n> arms and legs; the ONLY accent-colored part is the droplet tip. It MUST\n> perform the move, not decorate. {value rule: in a dark palette the body is\n> filled with the structure ink and the eyes are warm-white; in a light\n> palette the body is LIGHT with a structure-ink outline and structure-ink\n> eyes}\n\n## Custom character packs\n\nA character pack is a self-contained folder\n`${XDG_CONFIG_HOME:-~/.config}/illo/characters/<name>/` — the folder name is\nthe pack name, and the `doctor` subcommand lists what's installed:\n\n- `character.md` — the written spec: name, locked design, a **prompt spec**\n  paragraph for the CHARACTER slot, value rules, a `Style: <name>` line (the\n  pack's one look — a bundled or custom style; absent = riso), an optional\n  **`Cutout chroma: green|magenta`** line (the pack's cutout screen color —\n  used only by the OpenRouter/forced-chroma compatibility path; absent =\n  magenta; see `references/cutout.md`), an optional `Aliases:` line\n  (subject synonyms for \"use ox\"-style selection; see Naming above), an\n  optional **`## Interaction model`** section (fields above — packs without\n  one get the conservative derivation), and (optionally) personality notes.\n  Everything in \"Rules for any character\" above still applies.\n- `reference.png` — the character's model sheet, passed as `--ref` in place\n  of the default's. It is rendered **in the pack's style**, so sheet and\n  scenes always match.\n\nOne pack, one look. The same character in a different style is a sibling\n**style variant pack** (`<name>-<style>`, e.g. `blot-woodcut`) — built\ndeliberately via `references/character-builder.md`, \"Style variants\", with\nits own sheet and preview.\n\nA user can keep several packs and pick one per run by name; which character\nwins is SKILL.md step 2. Packs are portable — copying the folder to another\nmachine (or sharing it) installs the character. To design and install one\ninteractively, follow `references/character-builder.md`.\n\nFile v0.37.0:references/composition.md\n\n# Composition\n\nOne picture, one idea — turned into a single physical thing the mascot is\ncaught doing, in a small slightly-wrong machine-world, with quiet space around\nit.\n\n## Two registers\n\nEvery image is made in one of two registers. The methodology — thesis lock,\nshot list, load-bearing mascot, QA loop — is identical in both, and the look\nand palette stay whatever the character pack and `palettes.md` resolve; the\nregister only sets which image grammar is allowed.\n\n- **Editorial** (the default) — one caught scene: a physical move on one or\n  two built objects, meaning implied, no diagram machinery. Everything in\n  \"Turn the idea into a move\" and the stagings below.\n- **Explainer** — a hand-built sketch-diagram: stations, one flow direction,\n  callouts — for when the reader must be able to *trace* the structure, not\n  just feel it. Rules in \"The explainer register\" below.\n\nBefore choosing the register, infer the **artifact job**: what the requested\nimage is supposed to do for its audience in the place it will be seen. This is\nnot a keyword match; read the user's intent, destination, and source context.\nSome images are meant to explain a mechanism, but others are meant to introduce,\npromote, frame, or make a new offering legible as a standalone hero/poster. A\nstandalone introduction or announcement heroes the role, capability, or\nstep-change being claimed; mechanisms from the source become props, secondary\nactions, or small supporting labels. Do not route such an image to explainer\njust because the source contains a traceable process.\n\nEditorial wins every tie. Route an image to explainer only when:\n\n- **(a) the user asks for it** — \"show the flow\", \"diagram the pipeline\",\n  \"map the steps\", \"make it traceable\", \"as an explainer\", or names /\n  describes / alludes to a diagram type (\"as labeled stages\", \"like that\n  factory diagram\"; specified flowchart / labeled-workflow /\n  process-diagram intention locks labeled stages; full precedence in\n  \"Pick the diagram type\"); or\n- **(b) the unit's locked thesis IS a traceable structure** — its point\n  lives in the stations and their connections (a named pipeline or\n  labeled stages, a fan-out, a timeline, a loop, a layered stack), and one\n  caught moment would force the reader to take the structure on faith.\n\nA process that is merely *evidence* for a different lock stays editorial —\nthe lock is the arbiter, exactly as in Source routing step 2. Genres that\nmost often qualify: how-to / process and systems / architecture pieces.\nOpinions, quotes, launches, and anecdotes stay editorial: their theses are\nclaims, not structures. Like the mini-comic, the explainer is a deliberate\nchoice, never a fallback — and a set may mix registers (an editorial hero\nover explainer anchors is a natural article shape). Labeled stages is a\nstructure type *inside* this register, not a third register and not a\nnew look.\n\n## Turn the idea into a move\n\nStart from the one sentence the picture has to land, then find the **physical\nmove** that embodies it — something the mascot can be mid-action on. Push the\nabstract into the concrete: \"we ship too slowly\" → the mascot cranking a press\nthat drips a single parcel; \"we're buried in inputs\" → the mascot bailing a\nbucket that keeps overflowing. The move *is* the picture; until the move has\na name, there is no image yet.\n\nGive the move a **built thing to happen on or in** — a low-tech, faintly-broken\nmachine, container, or rig that the move implies. Invent it for this idea rather\nthan pulling from a stock set, and keep it to one or two objects, never a\ncluttered bench.\n\nThen put **the mascot in the move** — wedged in it, cranking it, plugging it,\nhauling across it — never posed politely beside it (see the load-bearing test\nin `character.md`). Locked silhouette and body proportions are\nnon-negotiable in every register, not only X Article banners. Dramatize\nscale by changing the **world** — a too-small door, a tiny hatch, an\noversized pile — never by stretching, squashing, or flattening the mascot\nto fill architecture or the frame. \"Subject large and confident ~50–70%\"\nis occupancy in the frame, not a license to distort the body.\n\n## Anatomy-action feasibility gate\n\nBefore locking the move, map every required contact to a part the active\ncharacter actually has — its interaction model (`character.md`). Write the\nmap as one line per contact:\n\n```text\ncharacter part -> object part -> contact location -> resulting motion\n```\n\nincluding a support line (what bears the weight) and where every inactive\nlimb rests. Example — the move \"drive the press\":\n\n```text\nright foot -> pedal  -> below body -> drives the press\nleft foot  -> ground -> below body -> supports weight\nboth arms  -> no contact -> low at the sides, outside the machine\n```\n\nThe gate applies in **both registers**: an explainer's mascot move — its\nstation, jam, sorter, or hauler role — maps its contacts the same way\nbefore the structure locks. Labeled stages pack-solves to **one** operator\nstage first (\"Labeled stages — skeleton, then pack-solve\"), then this gate\nruns on that one contact map. Confirm each active part is a declared contact\nsurface, can plausibly reach the contact without changing its locked\nsilhouette or body proportions, and that no object or route must cross a\nprotected region or fuse with the body. A move that only reads if the\nbody fills a door, hatch, or frame is a failed map — shrink or enlarge\nthe world object; do not squash the mascot. **Re-stage — a\ndifferent verb, object, orientation, or contact method — instead of\nprompting harder** when the map fails: a required surface the pack doesn't\ndeclare (undeclared fingers, hands, joints), a contact beyond the reach\nclass, more simultaneous contacts than the character has surfaces, a route\nthrough the face, ambiguous stroke ownership near the face or torso, a\nmove that only works by fusing the object into the body, or a pose that\nonly works by stretching or flattening the locked body. A load-bearing\nmove must be both conceptually necessary and physically drawable by this\ncharacter.\n\nThe validated map becomes the prompt's INTERACTION GEOMETRY block\n(`prompt-recipe.md`) and is the standard QA judges topology against\n(`quality-bar.md`).\n\n## Stagings that tend to land\n\nReach for whichever fits; these are starting angles, not a taxonomy to label on\nthe image:\n\n- **A contraption** — one absurd machine that performs the idea: small input, one output.\n- **A change** — the same scene in two states (jumbled → settled, by-hand → automatic).\n- **A throughput** — something travels left-to-right and is transformed on the way.\n- **A snag** — the whole thing jams at a single point, and the mascot is usually the jam.\n- **A build-up / drain** — it stacks, fills, leaks, or empties over time.\n- **A crossing** — a gap, gate, ramp, or threshold the mascot moves something over.\n- **A mini-comic** — 2–4 small panels inside ONE image, read left to right, one\n  action per panel; the mascot and the key object carry through every panel so\n  it reads as the same moment advancing (stuck → small slice → shipped).\n\nBlend sparingly; one clear staging beats two muddled ones. Across a set, vary\nthe stagings — two adjacent images shouldn't lean on the same staging or\nmetaphor family.\n\n## Pick the diagram type\n\nOnce the thesis is locked, pick the diagram type from that lock. The user\ncan override. An allusion is enough. After the type locks, do not rotate\nit for variety.\n\nSpecified intention locks the type even when the thesis would have stayed\neditorial. If the user names, describes, or alludes to a flowchart, a\nlabeled workflow, or a process diagram, lock labeled stages. That is\nintention — not a closed synonym list, and not a keyword scan of \"flow\"\nor \"workflow\". After the type locks, do not rotate it. The ban on\nboxes-and-diamonds / Visio / title-legend-grid formality is a **look**\nconstraint: produce labeled stages in the pack's look; do not refuse the\nword flowchart.\n\nOverride precedence (highest wins):\n\n1. The user **names** a type — \"as labeled stages\", \"label the steps\",\n   \"walk the stages\", \"timeline\", \"loop\", \"fan-out\", \"stack\",\n   \"as an explainer\", \"mini-comic\", \"just the scene\".\n2. The user **describes** a type — \"swim the stages\", \"one machine with\n   windows\". Specified intention includes (examples, not a closed list)\n   \"as a flowchart\", \"labeled workflow\".\n3. The user **alludes** to a type — \"like that factory diagram\".\n4. The agent default from the thesis map below.\n\nA named or alluded type locks both the register (when the type is a\ndiagram) and the type. \"As an explainer\" locks the register only — then\nthe map (or a more specific name) picks the structure. \"Mini-comic\" and\n\"just the scene\" lock those editorial shapes and skip the diagram.\n\nDefault only when the user did not steer. Labeled stages is BEST when\nthe thesis IS a named pipeline, recipe, or staged process — nameable\nstations in order, one connected system. Do not force labeled stages on\nevery explainer, and do not force explainer on a process that is merely\nevidence for a different lock.\n\n- A named pipeline, recipe, or staged process → **labeled stages** (inside\n  explainer): named phases in order, one connected system, in through\n  named stops then out, optional reject and/or return. The world is\n  invented from the thesis and the pack.\n- A split or sort → **fan-out**\n- Order or history → **timeline**\n- A cycle or feedback as the point → **loop**\n- Layers / a capability stack → **layer stack**\n- A few connected parts, no single direction → **system slice**\n- A story beat (fail→fix, before→after) → **mini-comic**, not a diagram\n  (the existing editorial shape)\n- A claim you can feel in one move → **editorial**, not a diagram\n- NEVER labeled stages unless the user specified that type: a claim you\n  can feel in one move; opinions, quotes, launches, anecdotes; a story\n  beat that is fail→fix / before→after (mini-comic); a split/sort\n  (fan-out); a cycle as the point (loop); layers (stack). Editorial\n  still wins every tie.\n- If two types fit, pick the one that makes the stations nameable\n- If none fit, do not force a diagram — editorial wins the tie, as in\n  \"Two registers\"\n\nThe register gate still applies: user asks, or the thesis IS a\ntraceable structure. Do not invent a look to \"read as a diagram\" —\nthe pack's existing style draws whatever type locks.\n\n## The explainer register\n\nOne structure, drawn as a hand-built sketch the mascot is working inside —\nnever a presenter beside a chart. The grammar editorial forbids (arrows,\nstations, a path) is the working material here; what stays forbidden is the\n*formal* version of it: no title, no border, no grid, no legend, no\nboxes-and-diamonds flowchart formality. That formality ban is a look\nconstraint — not a refusal of the word flowchart. A specified flowchart\nintention still draws labeled stages in the pack's look. The result must\nstill read as one artist's hand-built drawing in the active look.\n\nStructure types — pick ONE (these are the explainer's stagings; an explainer\nshot-list row names one of these in its staging slot). Labeled stages is\nthe staged, labeled form of a workflow; the other types stay as they are.\n\n- **Labeled stages** — a staged, labeled workflow: named phases in\n  order, one connected system, in through named stops then out,\n  optional reject and/or return. Lock the skeleton and run the\n  pack-solve below before drawing. The world is invented from the\n  thesis and the pack — a factory only when the thesis is a factory.\n- **A flow** — 3–5 stations left to right on one flow line; the\n  transformation is visible station to station. Use labeled stages when\n  the stages are a named pipeline or recipe, or when the user specified\n  a flowchart / labeled-workflow / process-diagram intention. Do not\n  treat that ask as this looser unlabeled flow.\n- **A fan-out / sort** — one source, the mascot routing, 2–4 labeled\n  destinations.\n- **A timeline** — one axis, 3–5 beats with short callouts; the order or\n  the spacing is the message.\n- **A loop / route** — a path with a few stops that visibly returns or\n  arrives; the return leg is drawn, not implied.\n- **A layer stack** — 3–4 informally stacked layers (hand-piled, never a\n  formal pyramid), the mascot building, carrying, or wedged under one.\n- **A system slice** — 3–5 connected parts of a system, the mascot\n  operating the one that matters.\n\nBudget (replaces the Restraint section's editorial numbers for this image):\n\n- **Stations ≤5**, each with a job a reader can name — a station that\n  explains nothing is clutter, and each is an invented physical thing in\n  the scene's world (a drawer cabinet, a press, a well — never a generic\n  rectangle).\n- **One main flow direction**, drawn as simple hand-drawn arrows in the\n  flow ink (semantic roles: `palettes.md`); at most one return or\n  exception leg.\n- **Callouts ≤6**, 1–4 short words each, two jobs: **station names**\n  (short, on the stations — where you are) and **arrow notes** (a verb\n  or condition ON the arrow — what happens between). Hand-lettered\n  directly on the bare paper/ground or on/along the arrow in the flow\n  ink — semantic ink roles per `palettes.md`, never on a colored fill.\n  Don't caption a station twice. Suggested split when the type is\n  labeled stages: ~3 station names + up to 2 arrow notes.\n- **The mascot is a working part** of the structure — a station, the jam,\n  the sorter, the hauler between stops — and passes the same load-bearing\n  test (`character.md`) and the anatomy-action feasibility gate (above).\n- Negative space floor stays (≥ ~35%); the structure may spread wider than\n  an editorial subject (~40–70% of the frame) but keeps one calm region.\n- The fresh-metaphor rule applies unchanged: reinvent the structure's\n  objects per piece; never recycle a previous diagram.\n\nSequence routing changes inside this register: a progression that would be a\nmini-comic in editorial is drawn as the flow itself here. Panels are\neditorial machinery — never mix panels and flow arrows in one image.\n\n**Labeled stages — skeleton, then pack-solve.** One connected system —\nnot five editorial islands, not a formal boxes-and-diamonds flowchart\nlook, not a title / legend / grid. The look stays the pack's: draw the system\nin riso, woodcut, clay, or whichever style the character already wears.\nDo not switch to a white doodle or whiteboard look to \"read as a\ndiagram.\" Do not default the world to a plant, a belt, or a hopper —\ninvent it from the thesis and the pack. A factory is a metaphor only\nwhen the thesis is a factory.\n\nLock this skeleton (content, style-agnostic) **before** drawing:\n\n- Input\n- 3–5 named stages (the thesis)\n- Output(s)\n- Optional reject and/or return\n\nStations are invented physical objects in the scene's world — never\ngeneric rectangles. One main flow direction. Callout budget stays the\nexplainer budget above (≤5 stations, ≤6 callouts, 1–4 words).\n\n**Arrow notes.** A second text job, not more plaques. Station names sit\non the stations (where you are). Arrow notes sit ON the arrow (what\nhappens between): the main flow arrow gets one verb; the return/reject\narrow gets one condition. Suggested split: ~3 station names + up to 2\narrow notes — still ≤6 total, each 1–4 words. Hand-letter arrow notes\non or along the arrow in the flow ink. Never a legend, a title bar, or\ncaptioning every station twice. Mute arrows (all plaques, no notes) and\nparagraph arrows both fail.\n\n**Pack-solve (required before the prompt).** Each character pack is\ndifferent. Reason from this body; do not template one factory. Write a\nshort internal scratch — stage list → operator stage → contact map →\nbind — then the image prompt:\n\n1. Read the active pack's `## Interaction model` (or derive\n   conservatively from the locked design per `character.md`): contact\n   surfaces, reach, grip, protected regions.\n2. Pick ONE stage this body can actually operate. Examples: Blot\n   (stubby, pressure/contact, no fingers) → a pedal, a press, a jam. A\n   long-armed pack → haul between stations. A no-limb / body-contact\n   pack → *be* the jam or the vessel. Prefer body-weight, pressing,\n   carrying, leaning over invented dexterity.\n3. Every other stage is a world object that MUST NOT require that\n   character's hands or undeclared contacts.\n4. Bind the stages into one connected system — not a row of\n   disconnected props. Invent the bind from the thesis and the pack.\n5. Run the anatomy-action feasibility gate (above) on the ONE contact\n   map. If it fails, restage the verb or which stage the mascot works —\n   not the thesis, not the stage names.\n6. Draw the system in the pack's existing look and palette.\n\nThen write the explainer prompt (`prompt-recipe.md`) from that scratch.\n\n## Source routing (URLs, articles, threads, long posts) — before any prompt\n\nFor any URL, pasted article, newsletter, thread, or long post, never\ngenerate from the first vivid detail — that produces an image of a\n*subclaim* while the piece's actual point goes unillustrated. Route in\nthree steps, before writing any prompt:\n\n**1. Classify the source — shape *and* genre** (internally — no need to show\nthe user). Shape sizes the coverage: single-claim short post · multi-claim\nshort post · long article / newsletter · procedural sequence or thread.\nGenre sets the hero logic: launch / announcement · failure report /\npostmortem · quote · how-to / process · benchmark / comparison · personal\nanecdote · opinion / argument. Genre matters because each one heroes a\ndifferent thing (the **Genre guardrails** below) — the same vivid detail\nthat's the headline in one genre is a supporting prop in another.\nAlso classify the requested artifact's job: is this image meant to introduce\nthe whole thing as a standalone opener/social card, support a section inside a\npiece, explain a mechanism, or provide a reusable visual asset? Let that job\nshape the hero and the text hierarchy. A launch source can contain a process,\nbut if the requested artifact is a hero/announcement, the process is evidence\nunless the source's actual promise is the process itself.\n\n**2. Lock the thesis — per coverage unit, not once per piece.** Write one\nsentence before any prompt: *\"This image must communicate: \\<thesis>.\"*\nThe thesis is scoped to the unit you are about to draw, and every image\ngets its own:\n\n- A **single image / hero** locks the *whole piece's* thesis. A launch\n  post listing six improvements is about the step-change they add up to\n  (\"runs farther with less steering\"), not about whichever list item\n  stages best.\n- A **set member** locks *its own section's* thesis — what that section\n  turns on — analyzed fresh, never sliced off the piece summary. Four\n  sections with four different angles must produce four different images;\n  if they all restate the headline, the per-section locks weren't done.\n\n**A hero locks the source's *job*, not its loudest evidence.** Separate\nthree things the source contains and do not confuse them: the **rhetorical\njob** (what the author wants the reader to believe or feel), the **primary\nclaim** (the one sentence that job reduces to — this is the hero thesis),\nand the **supporting mechanisms** (the concrete anecdotes/details that\n*prove* the claim). A load-bearing moment is usually a *supporting\nmechanism* — load-bearing for the argument, but evidence, not headline. It\nearns a spot as a **prop or secondary action** in the hero, or its own\nanchor in a set — never the hero itself, unless the source's job genuinely\n*is* that mechanism (a post whose whole point is \"measure, log, verify\"\nheroes measure/verify; a launch post that merely *mentions* careful\ndebugging does not). The classic miss: heroing the most drawable mechanism\nwhile the source's actual job — a role shift, a verdict, a warning — goes\nunillustrated.\n\nThen **draw the locked thesis, not the most drawable thing near it.** The\ntrap: the most *illustratable* moment is usually a supporting anecdote,\nnot the thesis — a concrete process (measure → log → verify) pictures in\none second while an abstract claim (judgment, taste, a step-change, \"now a\npartner not a tool\") resists. The easy picture is bait. When the thesis is\nabstract, do not retreat to whatever concrete activity the piece happens\nto describe; turn the abstract claim into a **role / scale / relationship\nmove** — tool→partner (climb out of the toolbox, pull up a chair),\nrung→higher rung, follows-orders→exercises-taste — the same \"turn the idea\ninto a move\" discipline applied to a quality claim, with the leftover\nmechanisms tucked in as small evidence props.\n\n**\"Subclaim\" is relative to the unit's own thesis.** Drawing a section's\npoint is correct for that section's image even though it's a \"supporting\ndetail\" of the whole — the subclaim filter rejects only what is smaller\nthan *this unit's* lock, never a section image for being smaller than the\narticle. **A process is the subject when it IS the locked thesis** (an\narticle section \"how X deploys\", a how-to whose point is the steps →\nmini-comic), and bait when it is merely evidence for a different lock (the\ndebugging anecdote under a \"it's a thinking partner now\" thesis). The lock\nis the arbiter; the shape rules below then carry whatever it named.\n\nFor multi-beat sources, pull the 3–7 load-bearing moments (criteria in the\nshot-list section below) before locking each.\n\n**Genre guardrails — what each genre heroes** (the rest become props or\nset anchors):\n\n- **Launch / announcement** → the new role, capability, or step-change\n  being claimed (the product/person/model *crossing into* what it now is).\n  Benchmarks, demos, and debugging anecdotes are supporting props.\n- **Failure report / postmortem** → the failed premise, the broken loop,\n  or the final outcome; individual incidents support it, not replace it.\n- **Quote** → the abstract relationship the quote names. Avoid an author\n  portrait or literal quote text unless the user asks.\n- **How-to / process** → the transformation it produces; a mini-comic only\n  when the *sequence itself* is the point (meaning lives between the steps).\n- **Benchmark / comparison** → the contrast or threshold crossed, not a\n  generic chart (charts are the forbidden register).\n- **Personal anec\n\nArchive v0.36.0: 38 files, 192070 bytes\n\nFiles: assets/checksums.txt (416b), NOTICE (703b), README.md (18963b), references/article-set-character-reroute.md (3926b), references/backends.md (17669b), references/character-builder.md (13383b), references/character.md (11398b), references/composition.md (34982b), references/cutout.md (14922b), references/models.md (6641b), references/pack-sharing.md (6682b), references/palettes.md (5453b), references/prompt-recipe.md (17802b), references/quality-bar.md (18521b), references/styles/bloom.md (5621b), references/styles/blueprint.md (2987b), references/styles/bricks.md (6652b), references/styles/chalk.md (2893b), references/styles/clay.md (3723b), references/styles/diorama.md (5521b), references/styles/enamel.md (3999b), references/styles/felt.md (5526b), references/styles/fizz.md (5299b), references/styles/gouache.md (3150b), references/styles/manila.md (3316b), references/styles/phosphor.md (3117b), references/styles/pixel.md (2919b), references/styles/sketchbook.md (6976b), references/styles/snes.md (8605b), references/styles/woodcut.md (2634b), references/surprise.md (28727b), references/visual-style.md (3482b), scripts/diagram_route.py (25195b), scripts/illo.py (102595b), scripts/repair-hermes-assets.sh (2137b), skill-card.md (2732b), SKILL.md (49052b), _meta.json (124b)\n\nArchive v0.35.0: 38 files, 190281 bytes\n\nFiles: assets/checksums.txt (416b), NOTICE (703b), README.md (18362b), references/article-set-character-reroute.md (3926b), references/backends.md (17669b), references/character-builder.md (13383b), references/character.md (11398b), references/composition.md (34982b), references/cutout.md (14922b), references/models.md (4490b), references/pack-sharing.md (6682b), references/palettes.md (5453b), references/prompt-recipe.md (17802b), references/quality-bar.md (18521b), references/styles/bloom.md (5621b), references/styles/blueprint.md (2987b), references/styles/bricks.md (6652b), references/styles/chalk.md (2893b), references/styles/clay.md (3723b), references/styles/diorama.md (5521b), references/styles/enamel.md (3999b), references/styles/felt.md (5526b), references/styles/fizz.md (5299b), references/styles/gouache.md (3150b), references/styles/manila.md (3316b), references/styles/phosphor.md (3117b), references/styles/pixel.md (2919b), references/styles/sketchbook.md (6976b), references/styles/snes.md (8605b), references/styles/woodcut.md (2634b), references/surprise.md (28727b), references/visual-style.md (3482b), scripts/diagram_route.py (25195b), scripts/illo.py (100372b), scripts/repair-hermes-assets.sh (2137b), skill-card.md (2598b), SKILL.md (49052b), _meta.json (124b)\n\nArchive v0.34.4: 37 files, 178114 bytes\n\nFiles: assets/checksums.txt (416b), NOTICE (703b), README.md (18032b), references/article-set-character-reroute.md (3912b), references/backends.md (17669b), references/character-builder.md (13383b), references/character.md (11109b), references/composition.md (26765b), references/cutout.md (14922b), references/models.md (4490b), references/pack-sharing.md (6682b), references/palettes.md (5453b), references/prompt-recipe.md (16480b), references/quality-bar.md (16370b), references/styles/bloom.md (5621b), references/styles/blueprint.md (2987b), references/styles/bricks.md (6652b), references/styles/chalk.md (2893b), references/styles/clay.md (3723b), references/styles/diorama.md (5521b), references/styles/enamel.md (3999b), references/styles/felt.md (5526b), references/styles/fizz.md (5299b), references/styles/gouache.md (3150b), references/styles/manila.md (3316b), references/styles/phosphor.md (3117b), references/styles/pixel.md (2919b), references/styles/sketchbook.md (6976b), references/styles/snes.md (8605b), references/styles/woodcut.md (2634b), references/surprise.md (28244b), references/visual-style.md (3482b), scripts/illo.py (100372b), scripts/repair-hermes-assets.sh (2137b), skill-card.md (2963b), SKILL.md (47576b), _meta.json (124b)\n\nArchive v0.34.3: 37 files, 176580 bytes\n\nFiles: assets/checksums.txt (416b), NOTICE (703b), README.md (17919b), references/article-set-character-reroute.md (3912b), references/backends.md (17001b), references/character-builder.md (13320b), references/character.md (11045b), references/composition.md (26765b), references/cutout.md (14765b), references/models.md (4449b), references/pack-sharing.md (6549b), references/palettes.md (5453b), references/prompt-recipe.md (16939b), references/quality-bar.md (16152b), references/styles/bloom.md (5621b), references/styles/blueprint.md (2987b), references/styles/bricks.md (6652b), references/styles/chalk.md (2893b), references/styles/clay.md (3723b), references/styles/diorama.md (5521b), references/styles/enamel.md (3999b), references/styles/felt.md (5526b), references/styles/fizz.md (5299b), references/styles/gouache.md (3150b), references/styles/manila.md (3316b), references/styles/phosphor.md (3117b), references/styles/pixel.md (2919b), references/styles/sketchbook.md (6976b), references/styles/snes.md (8470b), references/styles/woodcut.md (2634b), references/surprise.md (28244b), references/visual-style.md (3482b), scripts/illo.py (97240b), scripts/repair-hermes-assets.sh (2137b), skill-card.md (2862b), SKILL.md (47602b), _meta.json (124b)\n\nArchive v0.34.2: 37 files, 173419 bytes\n\nFiles: assets/checksums.txt (416b), NOTICE (703b), README.md (17919b), references/article-set-character-reroute.md (3912b), references/backends.md (17001b), references/character-builder.md (13320b), references/character.md (11045b), references/composition.md (26765b), references/cutout.md (10275b), references/models.md (4449b), references/pack-sharing.md (6549b), references/palettes.md (5453b), references/prompt-recipe.md (16939b), references/quality-bar.md (15741b), r...","readmeExcerpt":"Skill: illo Owner: tmchow Summary: Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the structure itself is the point, or a transparent character cutout (pose-only compositing asset, no scene or text) — in one of seventeen bundled looks (sixteen print, p","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"bash ${HERMES_SKILL_DIR}/scripts/repair-hermes-assets.sh"},{"language":"bash","snippet":"SKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" doctor"},{"language":"bash","snippet":"SKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" init --backend grok-bot --no-key"},{"language":"bash","snippet":"SKILL_DIR=\"<path to this skill>\";\npython3 \"$SKILL_DIR/scripts/illo.py\" init --backend muse-native --no-key"},{"language":"bash","snippet":"SKILL_DIR=\"<path to this skill>\";\nREF=\"$SKILL_DIR/assets/character-reference.webp\";\npython3 \"$SKILL_DIR/scripts/illo.py\" generate --prompt-file /tmp/shot-01.txt --ref \"$REF\" --aspect 16:9 --out \"assets/<slug>-illustrations/01-topic.png\""},{"language":"bash","snippet":"SKILL_DIR=\"<path to this skill>\";\nRUN=$(python3 \"$SKILL_DIR/scripts/illo.py\" newrun);\nprintf '%s' \"<the verbatim request>\" > \"$RUN/request.txt\"\n# (a) VARIATIONS — same prompt+model, pick-the-best:\npython3 .../illo.py generate --prompt-file p.txt --ref <ref> --count 4 --label \"draft→ship\" --out \"$RUN/v.png\"\n# (b) MODEL COMPARISON — loop the SAME prompt over the chosen models\n#     (full OpenRouter ids from references/models.md):\nfor m in <model-id-1> <model-id-2>; do\n  python3 .../illo.py generate --prompt-file p.txt --ref <ref> --model \"$m\" --label \"$m\" --out \"$RUN/$(basename $m).png\"; done\n# (c) CONCEPT VARIATIONS — different prompts (different stagings) for one idea:\npython3 .../illo.py generate --prompt-file staging-A.txt --ref <ref> --label \"as a funnel\" --out \"$RUN/a.png\"\npython3 .../illo.py generate --prompt-file staging-B.txt --ref <ref> --label \"as a crossing\" --out \"$RUN/b.png\"\n\npython3 \"$SKILL_DIR/scripts/illo.py\" gallery \"$RUN\" --title \"<the piece or request>\" --open\n# always pass --title so a saved gallery stays identifiable later;\n# add --embed for a single portable file (images inlined)"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: illo\ndescription: >-\n  Creates original editorial illustrations where a recurring mascot\n  character performs the idea — one caught scene by default, a hand-built\n  explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the\n  structure itself is the point, or a transparent character cutout\n  (pose-only compositing asset, no scene or text) — in one of seventeen bundled\n  looks (sixteen print, plus a photoreal toy-brick set). Also handles\n  \"surprise me\" / \"random\" (optionally scoped to a focus or character): rolls\n  provenance, builds three saying candidates, picks via interactive choice or\n  auto-pick-best (`--autopick`), and renders one image. Triggers only when\n  the skill is directly invoked or \"illo\" is requested; never on generic\n  illustrate / draw / make-an-image requests.\n# x-release-please-start-version\nversion: 0.37.0\n# x-release-please-end\nargument-hint: \"[idea or article URL] | build a character | install <character> | surprise me [focus] [--autopick] [using character]\"\nauthor: Trevin Chow\nlicense: MIT\nmetadata:\n  hermes:\n    tags: [illustration, riso, image-generation, editorial, mascot, codex, grok, openrouter, muse]\n    category: creative\n    requires_toolsets: [terminal]\n  openclaw:\n    emoji: \"🎨\"\n    homepage: https://illo-skill.com\n    os: [macos, linux]\n    requires:\n      bins: [python3]\n---\n\n# Illo\n\nMake original, distinctive editorial illustrations for written content. One\nimage explains one idea: a key judgment, a flow, a before/after, a trap, a\nloop. A **recurring mascot** is the one performing the idea in every scene —\nthe subject, never decoration. When one idea advances through stages, it can\nbe a **mini-comic**: 2–4 panels inside a single image. And when the idea is\nitself a traceable structure — a pipeline, labeled stages, a fan-out, a\ntimeline, a loop — it can be an **explainer**: the same mascot and look\ndrawing the structure as a hand-built sketch-diagram with arrows and\ncallouts (`references/composition.md`, \"Two registers\" and \"Pick the\ndiagram type\"; editorial scene is always the default). A named pipeline\nor recipe is **labeled stages** inside that register — named phases in\norder, one connected system, pack-solved for this body, never a new look.\nOr a **character cutout**: the mascot alone on a transparent PNG for downstream overlay\n— pose and contact continuity only, no idea, no text, no environment\n(`references/cutout.md`).\n\nThis is a configurable house style, not a generic image generator. The\n**methodology is the constant**; the **character pack and palette are the\nparameters** — and a character pack carries its **style** with it: one look\nper pack, chosen from the bundled look library (riso — grainy halftone,\nink-layer offset, paper grain, one bold softly-rounded outline — plus\nblueprint, woodcut, pixel, clay, manila, chalk, phosphor, enamel,\ngouache, felt, diorama, sketchbook, bricks, fizz, bloom, and snes) or a custom style file. The default mascot is\n**Blot**, a deadpan"},{"path":"README.md","content":"# Illo\n\n**[illo-skill.com](https://illo-skill.com)** — live examples, character packs,\nand copy-paste installs. This file is the developer reference (engines,\nmodels, cost, API keys).\n\nTurn a concept or an article into original **editorial illustrations** —\nflat, bold-lined print-style scenes where a recurring mascot performs the\nidea. One image says one thing: a key judgment, a flow, a before/after, a\ntrap. It's a deliberate house style, not a generic image generator — closer\nto a smart, deadpan print zine than to clip art or an infographic.\n\nThe methodology is the constant; **the character pack and palette are yours\nto set** — and every character pack carries its own print style. Out of the\nbox the mascot is **Blot**, a deadpan ink-drop in **risograph**. A built-in\n**character builder** designs your own mascot with you (interview — including\npicking its look from the bundled library of seventeen ([below](#looks)) — then\nmodel-sheet candidates → pick → install). Want the same\ncharacter in another look? Build a *style variant pack* (`blot-woodcut`):\none pack, one look, so a catalog of characters never turns into a grid of\ncombinations. Palettes stay per-image and resolve by **destination**: a\ncharacter defines *where* its accent lives, never the color. One plain-text\nline in your palettes file — `blog → notes` — and anything headed for your\nblog automatically wears `notes`, a palette built once by copying your\nsite's real CSS colors into hexes (background → paper, text → ink, link\ncolor → accent; re-extract only if you rebrand). Same mascot, fluoro pink\non X, your blog's exact orange on the blog — never asked twice. Or pick a\nnamed preset, or hand it one brand color and let it derive the rest.\n\n![Blot — the default mascot](assets/character-reference.webp)\n\n> **Invoking:** the skill answers to its name — say **\"illo\"** (\"illo this\n> post\", \"use illo: draw blip hauling a crate\"). It deliberately won't hijack\n> generic requests like \"illustrate this post\", and it can't know your\n> installed characters' names up front — lead with \"illo\", then talk\n> characters freely.\n\nSame character, different voice — the bundled woodcut style telling a\nthree-panel story:\n\n![Woodcut mini-comic example](https://raw.githubusercontent.com/tmchow/illo-skill/main/_assets/illo/styles/woodcut-minicomic.png)\n\nAnd the day job — compressing an abstract concept into one scene that lands\nin about a second. Hand it *\"we replatform with zero downtime\"* and you get\nthe bridge being rebuilt under live traffic:\n\n![Zero downtime — rebuilding the bridge under live traffic](https://raw.githubusercontent.com/tmchow/illo-skill/main/_assets/illo/05-bridgeswap-ink-punch.png)\n\nOne idea per image, the mascot *performing* the move rather than decorating\nit, a few short hand-lettered labels — every render is held to that\nbar, and off-model results get re-rolled before you see them.\n\n## Looks\n\nEvery character pack picks exactly one look from the bundled library:\n\n| Look | The voice |\n|---|---|\n"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7ey3j7hw5sw95h24y5scayc57zz8rf\",\n  \"slug\": \"illo\",\n  \"version\": \"0.37.0\",\n  \"publishedAt\": 1790022053020\n}"},{"path":"references/article-set-character-reroute.md","content":"# Article-set character reroute\n\nUse this gate when an article/newsletter set is being rerouted to a different\ncharacter after a weak or failed attempt, or whenever a new mascot/domain world\nis introduced for a technical or platform essay. The expensive failure mode is\nnot bad drawing; it is a handsome set whose private metaphor system no longer\nmaps to the article.\n\n## Mandatory legibility preflight\n\nBefore spending any renders, write a preflight row for every proposed shot:\n\n- **Section claim** — the section-level thesis this image must land, in plain\n  article language.\n- **Visual object/action** — the one object and mascot action that will be\n  visible in the frame.\n- **Reader mapping** — how a reader gets from that object/action back to the\n  section claim without seeing your notes.\n\nReject or rewrite the shot if the mapping needs either of these:\n\n- a private metaphor glossary (\"in this world, the cactus means infra debt\");\n- more than one conceptual substitution before the claim becomes clear.\n\nOne clean metaphor is allowed and often good. The test is whether the reader can\nname it from the scene, not whether it is literal.\n\n## Technical / platform essays\n\nFor technical, infrastructure, SaaS, protocol, or platform pieces, default the\ncore scene to native article primitives the reader already knows: accounts,\npermissions, meters, tokens, gates, ledgers, switches, apps, providers, queues,\nkeys, quotas, bills, routes. Let the character pack's domain world supply the\naccent, posture, and action — not the entire conceptual system.\n\nGood reroute shape: the mascot pushes a permission gate, carries a token across\na provider switch, patches a leaky meter, or reconciles a ledger. Risky reroute\nshape: every concept becomes a character-world object that must be decoded\nbefore the article's claim can be read.\n\nThis is not a license to flatten the work into stock SaaS diagrams. Keep the\nillo house style: one fresh physical move, one invented built object, quiet\nspace, and a load-bearing mascot. Avoid generic dashboards, formal charts,\nUI mockups, and literal office art.\n\n## Hero before style anchor\n\nIn a hero + set, the rerouted hero may become the style anchor only after it\npasses both gates:\n\n1. **Visual quality** — normal quality bar: on-model mascot, palette, restraint,\n   composition, no artifact/title failures.\n2. **Thesis legibility** — a reader can connect the scene to the piece's central\n   claim without a private glossary or a chain of substitutions.\n\nA visually strong but illegible hero is not a safe second reference; it will\npropagate the wrong metaphor into the whole set.\n\n## Explainer mode and labels\n\nExplainer register is valid for multi-image article sets when a section needs a\ntraceable structure. Technical sections often become more legible as labeled\nstages, flow, fan-out, timeline, loop, stack, or system slice than as a pure\neditorial scene.\nKeep it hand-built and character-led, not a formal flowchart.\n\nLabels and titles are not forb"},{"path":"references/backends.md","content":"# Backends and transports\n\nillo has **three engine backends** plus one named **agent-side transport**. All\nproduce the same kind of file; they differ in where the image is made, how the\nagent reaches it, and who is billed.\n\n- **Codex** — drives the user's already-installed, already-logged-in **Codex\n  CLI** (`codex exec`) to reach its built-in `image_generation` tool\n  (gpt-image-2). Free for Codex subscribers (no per-image charge); it draws\n  on the user's Codex usage quota.\n- **Grok CLI** — drives the user's **Grok (xAI) CLI** (`grok -p`, its headless\n  single-turn mode) to reach its built-in `image_gen`/`image_edit` tools. Free\n  for Grok subscribers; draws on the user's Grok usage quota. Same env-free,\n  token-free subprocess design as Codex. **Cannot produce transparent cutouts**\n  (Grok returns JPEG with no alpha) — cutout renders redirect to a\n  cutout-capable backend.\n- **Grok Bot native** — when the agent is **Grok Bot** (Cursor's Grok Bot /\n  the Grok desktop assistant), the agent persists `backend: grok-bot` with\n  `init --backend grok-bot --no-key`, then calls Grok Bot's built-in Grok image\n  tool directly with illo's prompt and reference image. This is the same Grok\n  image-model class as the CLI backend, but a different harness: no Grok CLI and\n  no OpenRouter key. It is not a generic \"any host image API\" escape hatch.\n- **OpenRouter** — calls OpenRouter's image API directly. Pay-per-image\n  through the user's OpenRouter account. The direct paid backend and the only\n  engine backend a host without a subscription CLI can use. A failed CLI render\n  reaches it only when `--allow-paid-fallback` is explicitly supplied;\n  intentional cutout routing is unchanged.\n\n`--backend` (and config `backend:`) selects an engine backend or the explicit\nagent-side `grok-bot` transport; otherwise the engine resolves the right engine\nbackend by host capability. Resolution and readiness are reported by `doctor`.\n`illo.py generate` refuses `grok-bot` because only the Grok Bot agent can call\nits native image tool.\n\n## Engine resolution and default (capability-aware)\n\nThe backend is resolved per run, never a static flip:\n\n```\n--backend  >  config backend:  >  capability-aware engine default\n```\n\nThe **capability-aware engine default** is, in order:\n\n1. a **usable Codex CLI** is present → `codex`;\n2. else a **usable Grok CLI** is present → `grok`;\n3. else an **OpenRouter key** is configured → `openrouter`;\n4. else none → onboarding (the engine names the fixes).\n\nThis never silently breaks an existing OpenRouter-only install on upgrade: a\nhost with a key but no subscription CLI still resolves to `openrouter`, so\n`doctor` stays exit 0. `grok-bot` is never auto-detected; the Grok Bot agent\nself-identifies by running `init --backend grok-bot --no-key`. An explicit\n`--backend`/`backend:` choice is honored as-is; readiness is judged separately,\nso `doctor` can flag a chosen-but-unusable backend or green-light `grok-bot`.\n\n### The self-identify rule (agent-driven, n"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the structure itself is the point, or a transparent character cutout (pose-only compositing asset, no scene or text) — in one of seventeen bundled looks (sixteen print, plus a photoreal toy-brick set). Also handles \"surprise me\" / \"random\" (optionally scoped to a focus or character): rolls provenance, builds three saying candidates, picks via interactive choice or auto-pick-best (`--autopick`), and renders one image. Triggers only when the skill is directly invoked or \"illo\" is requested; never on generic illustrate / draw / make-an-image requests. Skill: illo Owner: tmchow Summary: Creates original editorial illustrations where a recurring mascot character performs the idea — one caught scene by default, a hand-built explainer diagram (labeled stages, a fan-out, timeline, loop, or stack) when the structure itself is the point, or a transparent character cutout (pose-only compositing asset, no scene or text) — in one of seventeen bundled looks (sixteen print, p","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":2328,"uniquenessScore":45,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T09:56:01.893Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T09:56:01.893Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T14:58:01.791Z","emptyReason":null},"items":[{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-10T18:48:31.762Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}