@gobing-ai/knowledge-kit 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/dist/index.js +100 -26
  2. package/package.json +1 -1
  3. package/plugins/generations/content-gen/dist/index.js +22167 -0
  4. package/plugins/generations/content-gen/plugin.json +1 -1
  5. package/plugins/generations/core-facts-gen/dist/index.js +22048 -0
  6. package/plugins/generations/core-facts-gen/plugin.json +1 -1
  7. package/plugins/generations/daily-article-gen/dist/index.js +22022 -0
  8. package/plugins/generations/daily-article-gen/plugin.json +1 -1
  9. package/plugins/generations/dailynews-gen/dist/index.js +22324 -0
  10. package/plugins/generations/dailynews-gen/plugin.json +1 -1
  11. package/plugins/generations/episode-plan-gen/dist/index.js +22479 -0
  12. package/plugins/generations/episode-plan-gen/plugin.json +1 -1
  13. package/plugins/generations/image-gen/config.example.yaml +75 -0
  14. package/plugins/generations/image-gen/dist/index.js +22619 -0
  15. package/plugins/generations/image-gen/package.json +17 -0
  16. package/plugins/generations/image-gen/plugin.json +7 -0
  17. package/plugins/generations/image-gen/presets/formats/cover.yaml +57 -0
  18. package/plugins/generations/image-gen/presets/formats/free.yaml +46 -0
  19. package/plugins/generations/image-gen/presets/formats/illustration.yaml +48 -0
  20. package/plugins/generations/image-gen/presets/styles/clean-webapp-ui.yaml +28 -0
  21. package/plugins/generations/image-gen/presets/styles/cute.yaml +3 -0
  22. package/plugins/generations/image-gen/presets/styles/editorial.yaml +3 -0
  23. package/plugins/generations/image-gen/presets/styles/fresh.yaml +3 -0
  24. package/plugins/generations/image-gen/presets/styles/minimalist.yaml +3 -0
  25. package/plugins/generations/image-gen/presets/styles/photorealistic.yaml +3 -0
  26. package/plugins/generations/image-gen/presets/styles/sketch.yaml +3 -0
  27. package/plugins/generations/image-gen/presets/styles/technical-diagram.yaml +3 -0
  28. package/plugins/generations/image-gen/presets/styles/vibrant.yaml +3 -0
  29. package/plugins/generations/image-gen/presets/styles/warm.yaml +3 -0
  30. package/plugins/generations/image-gen/src/bytes.ts +19 -0
  31. package/plugins/generations/image-gen/src/index.ts +319 -0
  32. package/plugins/generations/image-gen/src/job.ts +143 -0
  33. package/plugins/generations/image-gen/src/paths.ts +31 -0
  34. package/plugins/generations/image-gen/src/presets.ts +344 -0
  35. package/plugins/generations/image-gen/src/providers/seedream.ts +128 -0
  36. package/plugins/generations/image-gen/src/providers/types.ts +285 -0
  37. package/plugins/generations/image-gen/tsconfig.json +8 -0
  38. package/plugins/generations/voice-gen/dist/index.js +23027 -0
  39. package/plugins/generations/voice-gen/plugin.json +1 -1
  40. package/plugins/ingestions/aihot-ingest/dist/index.js +22358 -0
  41. package/plugins/ingestions/aihot-ingest/plugin.json +1 -1
  42. package/plugins/ingestions/horizon-ingest/dist/index.js +22105 -0
  43. package/plugins/ingestions/horizon-ingest/plugin.json +1 -1
  44. package/plugins/ingestions/karakeep-local/dist/index.js +24204 -0
  45. package/plugins/ingestions/karakeep-local/plugin.json +1 -1
  46. package/plugins/ingestions/last30days-ingest/dist/index.js +22050 -0
  47. package/plugins/ingestions/last30days-ingest/plugin.json +1 -1
  48. package/plugins/ingestions/web-search/dist/index.js +24379 -0
  49. package/plugins/ingestions/web-search/plugin.json +1 -1
  50. package/plugins/kk/commands/image-generate.md +15 -0
  51. package/plugins/kk/config.example.yaml +80 -0
  52. package/plugins/kk/skills/image-authoring/SKILL.md +250 -0
  53. package/plugins/kk/skills/image-authoring/references/illustration-positions.md +87 -0
  54. package/plugins/kk/skills/image-authoring/references/migrating-from-wt.md +31 -0
  55. package/plugins/kk/skills/image-authoring/references/providers.md +52 -0
  56. package/plugins/kk/skills/image-authoring/references/style-extraction.md +134 -0
  57. package/plugins/publishings/emdash-pub/dist/index.js +22243 -0
  58. package/plugins/publishings/emdash-pub/plugin.json +1 -1
  59. package/plugins/publishings/podcast-pub/dist/index.js +22596 -0
  60. package/plugins/publishings/podcast-pub/plugin.json +8 -2
  61. package/plugins/publishings/qiita-pub/dist/index.js +22081 -0
  62. package/plugins/publishings/qiita-pub/plugin.json +1 -1
  63. package/plugins/publishings/surfdash-pub/dist/index.js +22233 -0
  64. package/plugins/publishings/surfdash-pub/plugin.json +1 -1
  65. package/plugins/publishings/zenn-pub/dist/index.js +22122 -0
  66. package/plugins/publishings/zenn-pub/plugin.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "web-search",
3
3
  "kind": "ingestion",
4
- "entry": "./src/index.ts",
4
+ "entry": "./dist/index.js",
5
5
  "version": "1.0.0",
6
6
  "description": "Ingests web search results for a topic into Doc objects (fixture stub — no live Firecrawl in v1)"
7
7
  }
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: image-generate
3
+ description: Generate images from a prompt or an article — covers, illustrations, or free-form — using named format and style presets.
4
+ argument-hint: "[prompt] [--format <name>] [--style <name>] [--content <file>] [--ref <path>] [--var K=V] [--dry-run] [--list-presets]"
5
+ allowed-tools: ["Skill"]
6
+ ---
7
+
8
+ # image-generate
9
+
10
+ Thin wrapper for the `image-authoring` skill — all preset resolution, preference precedence,
11
+ confirmation and delegation logic lives in the skill. Forward `$ARGUMENTS` unchanged.
12
+
13
+ ```text
14
+ Skill(skill="kk:image-authoring", args="$ARGUMENTS")
15
+ ```
@@ -22,6 +22,73 @@ plugins:
22
22
  VOICEBOX_POLL_MS: "1000" # GET /history/{id} interval
23
23
  VOICEBOX_MAX_CHUNK_CHARS: "800" # Voicebox auto-chunk size (100–5000)
24
24
  VOICEBOX_CROSSFADE_MS: "50" # Voicebox chunk crossfade (0–500)
25
+
26
+ # image-gen (task 0103/0104): full credential inventory, placeholder values only —
27
+ # source of truth: plugins/generations/image-gen/config.example.yaml
28
+ image-gen:
29
+ env:
30
+ # -- google (Gemini multimodal + Imagen; GOOGLE_* and GEMINI_* are fallback pairs) --
31
+ GOOGLE_API_KEY: "" # or GEMINI_API_KEY — either one enables google
32
+ GEMINI_API_KEY: ""
33
+ GOOGLE_IMAGE_MODEL: "" # optional — default gemini-3-pro-image
34
+ GOOGLE_BASE_URL: "" # optional — default https://generativelanguage.googleapis.com
35
+ # -- openai (gpt-image generations/edits; OPENAI_IMAGE_USE_CHAT is a debug escape hatch) --
36
+ OPENAI_API_KEY: "" # platform.openai.com — required for openai
37
+ OPENAI_IMAGE_MODEL: "" # optional — default gpt-image-2
38
+ OPENAI_BASE_URL: "" # optional — default https://api.openai.com/v1
39
+ OPENAI_IMAGE_USE_CHAT: "" # optional — "true" routes through chat completions
40
+ # -- openrouter (multi-host gateway) --
41
+ OPENROUTER_API_KEY: "" # openrouter.ai/settings/keys — required for openrouter
42
+ OPENROUTER_IMAGE_MODEL: "" # optional — default google/gemini-3.1-flash-image
43
+ OPENROUTER_BASE_URL: "" # optional — default https://openrouter.ai/api/v1
44
+ OPENROUTER_HTTP_REFERER: "" # optional — attribution header
45
+ OPENROUTER_TITLE: "" # optional — attribution header
46
+ # -- dashscope (Alibaba; refs only on wan2.7 models) --
47
+ DASHSCOPE_API_KEY: "" # required for dashscope
48
+ DASHSCOPE_IMAGE_MODEL: "" # optional — default qwen-image-2.0-pro
49
+ DASHSCOPE_BASE_URL: "" # optional — default https://dashscope.aliyuncs.com
50
+ # -- zai (Z.AI / bigmodel.cn; refs unsupported) --
51
+ ZAI_API_KEY: "" # or BIGMODEL_API_KEY — either one enables zai
52
+ BIGMODEL_API_KEY: ""
53
+ ZAI_IMAGE_MODEL: "" # optional — default glm-image
54
+ BIGMODEL_IMAGE_MODEL: ""
55
+ ZAI_BASE_URL: "" # optional — default https://api.z.ai/api/paas/v4
56
+ BIGMODEL_BASE_URL: ""
57
+ # -- minimax (image-01; refs via subject_reference, jpg/png <10MB) --
58
+ MINIMAX_API_KEY: "" # required for minimax
59
+ MINIMAX_IMAGE_MODEL: "" # optional — default image-01
60
+ MINIMAX_BASE_URL: "" # optional — default https://api.minimaxi.com
61
+ # -- replicate (hosted model surface; prediction polling) --
62
+ REPLICATE_API_TOKEN: "" # replicate.com/account/api-tokens — required for replicate
63
+ REPLICATE_IMAGE_MODEL: "" # optional — default google/nano-banana-2
64
+ REPLICATE_BASE_URL: "" # optional — default https://api.replicate.com
65
+ # -- jimeng (Volcengine; BOTH key halves required, HMAC-signed) --
66
+ JIMENG_ACCESS_KEY_ID: "" # required for jimeng (with the secret key)
67
+ JIMENG_SECRET_ACCESS_KEY: "" # required for jimeng (with the access key)
68
+ JIMENG_IMAGE_MODEL: "" # optional — default jimeng_t2i_v40
69
+ JIMENG_REGION: "" # optional — default cn-north-1
70
+ JIMENG_BASE_URL: "" # optional — default https://visual.volcengineapi.com
71
+ # -- seedream (ByteDance Ark; key is ARK_API_KEY, not SEEDREAM_*) --
72
+ ARK_API_KEY: "" # required for seedream
73
+ SEEDREAM_IMAGE_MODEL: "" # optional — default doubao-seedream-5-0-260128
74
+ SEEDREAM_BASE_URL: "" # optional — default https://ark.cn-beijing.volces.com/api/v3
75
+ # -- azure (Azure OpenAI; model is addressed by deployment name) --
76
+ AZURE_OPENAI_API_KEY: "" # required for azure
77
+ AZURE_OPENAI_BASE_URL: "" # required resource endpoint, e.g. https://<res>.openai.azure.com
78
+ AZURE_OPENAI_DEPLOYMENT: "" # deployment hosting a gpt-image model
79
+ AZURE_OPENAI_IMAGE_MODEL: "" # optional — default gpt-image-2
80
+ AZURE_API_VERSION: "" # optional — default 2025-04-01-preview
81
+ # -- agnes (OpenAI-compatible images endpoint) --
82
+ AGNES_API_KEY: "" # required for agnes
83
+ AGNES_IMAGE_MODEL: "" # optional — default agnes-image-2.1-flash
84
+ AGNES_BASE_URL: "" # optional — default https://apihub.agnes-ai.com/v1
85
+ # -- codex-cli (subprocess; NEVER auto-selected — pin explicitly) --
86
+ BAOYU_CODEX_IMAGEGEN_BIN: "" # optional — wrapper entrypoint override
87
+ BAOYU_CODEX_IMAGEGEN_TIMEOUT_MS: "" # optional — per-call timeout (ms)
88
+ BAOYU_CODEX_IMAGEGEN_RETRIES: "" # optional — retry count
89
+ # -- 0104 R6 runtime seams (behavior, not credentials; placeholder values only) --
90
+ KK_IMAGE_MAX_IMAGES: "" # optional — per-run budget cap; default 4 (OPEN for the operator to set)
91
+ KK_IMAGE_DRY_RUN: "" # optional — "1" composes every prompt, selects the provider, spends nothing
25
92
  publishings:
26
93
  qiita-pub:
27
94
  env:
@@ -32,3 +99,16 @@ plugins:
32
99
  surfdash-pub:
33
100
  env:
34
101
  POSTSURFING_BIN: "" # optional — delete if unused; defaults to `postsurfing` on PATH
102
+
103
+ # Image-authoring preferences (task 0106) — read by the kk:image-authoring skill,
104
+ # not by the plugin; the plugin sees only the resolved winners in its --in envelope.
105
+ # Precedence: arguments > environment (KK_IMAGE_*) > this block > compiled defaults.
106
+ # Credentials never live here — see plugins.generations.image-gen.env above.
107
+ image:
108
+ format: free # default --format
109
+ style: ~ # ~ = use the format's defaultStyle
110
+ provider: ~ # ~ = auto (0103 AUTO_ORDER)
111
+ model: ~
112
+ auto_confirm: false # baoyu's quick_mode, renamed to say what it does
113
+ max_images: 4 # mirrors KK_IMAGE_MAX_IMAGES (0104)
114
+ preset_path: ~ # extra roots, ':'-separated → KK_IMAGE_PRESET_PATH
@@ -0,0 +1,250 @@
1
+ ---
2
+ name: image-authoring
3
+ description: >-
4
+ Use the image-authoring skill to generate images — "generate an image",
5
+ "create a cover for this article", "illustrate this article", "make a hero
6
+ image", "extract a style from this reference image", "clone this look",
7
+ "list the image formats and styles". Three operations — generate,
8
+ extract-style, list-presets — over named format and style presets, with a
9
+ confirmation gate before any paid generation.
10
+ ---
11
+
12
+ # image-authoring — image generation agent surface (generate | extract-style | list-presets)
13
+
14
+ ## Purpose
15
+
16
+ Turn an operator request into **generated or derived image artefacts** by driving the
17
+ deterministic `kk:image-gen` generator plugin. One fat skill with three operations —
18
+ `generate` (default), `extract-style`, `list-presets` — sharing one invocation contract,
19
+ `--in` envelope, preference chain and confirmation policy. The job is not an operation:
20
+ it is **data** — each format preset declares its own `job` field
21
+ (0102), and `--format` selects the work. This is the `audio-authoring` shape applied to
22
+ a job axis that lives in YAML.
23
+
24
+ **The judgment line — the plugin executes a decided plan; this skill decides it.** The
25
+ plugin (`plugins/generations/image-gen/`) is deterministic: preset resolution and
26
+ shadowing, prompt composition, provider selection and the API call, artefact naming and
27
+ writing, and markdown insertion at a given anchor. Everything needing reading, taste or
28
+ ambiguity resolution is **this skill's**: deriving `--var` values from an article (title,
29
+ subtitle, topics), style auto-detection, illustration **position detection**, caption and
30
+ alt-text authoring, style extraction from reference images, preference precedence
31
+ resolution, and spend approval. The skill's single output to the engine is the `--in`
32
+ envelope; nothing model-shaped ever crosses it.
33
+
34
+ ## When to use
35
+
36
+ - A user asks for an image: a free-form picture from a prompt, a cover for an article,
37
+ or illustrations inserted into an article body.
38
+ - A user hands over reference images wanting the look captured as a reusable style
39
+ preset, or asks what formats and styles exist.
40
+ - A workflow `agent.run` step needs one image job non-interactively (Confirmation
41
+ policy — the node must set `KK_NONINTERACTIVE=1`).
42
+
43
+ ## Do not use this skill for
44
+
45
+ - Speech or spoken-audio authoring (that is `kk:audio-authoring`).
46
+ - Hand-written programmatic generation: call `kk executor run image-gen` directly with
47
+ your own `--in` envelope — this skill's value is the deciding, not the spawn.
48
+ - Editing an existing image (image-to-image): regenerate with a tweaked prompt instead.
49
+ - A coordinator subagent over this skill: none is wanted; `/kk:image-generate` is the
50
+ whole entry surface.
51
+
52
+ ## Operations
53
+
54
+ ### generate (default)
55
+
56
+ Sequence: **resolve preferences** (Preference chain) → **resolve the format** →
57
+ **validate arguments** → **decide the work** → **confirm** (Confirmation policy) →
58
+ **preview** (`KK_IMAGE_DRY_RUN=1`) → **paid run** → **report**.
59
+
60
+ 1. Resolve the format preset from `--format` and read its `job` field — that is the
61
+ branch. Never hardcode format names: an operator-authored format must work with
62
+ zero edits here (its `job` field is the only fact the skill needs).
63
+ 2. If the `job` value is one of the branches below, proceed. Anything else: **stop,
64
+ name the unimplemented branch and the format**, and never fall back to `free`.
65
+ - `free` — the positional prompt is the subject; no `--content` needed.
66
+ - `cover` — read `--content` and derive the format's template variables from the
67
+ article (title, subtitle, topics) — model work, this skill's — into `vars`.
68
+ - `illustration` — detect insertion positions and author captions per
69
+ [references/illustration-positions.md](references/illustration-positions.md);
70
+ the chosen anchors cross as `metadata.positions`, one image per anchor.
71
+ 3. Resolve the style: `--style`, else the preference `image.style`, else the format's
72
+ `defaultStyle`. Without an explicit choice the skill may propose an auto-detected
73
+ style — taste, this skill's — shown in the preview for approval.
74
+ 4. Resolve the provider and model per Preference chain; the credential and
75
+ reference-image facts per provider live in
76
+ [references/providers.md](references/providers.md).
77
+ 5. Write the `--in` envelope (Artifact contract), then follow the Confirmation policy.
78
+ 6. Report the `--out` path, every artefact, and for illustration the captions.
79
+ `--dry-run` stops after the preview and reports the composed prompt.
80
+
81
+ ### extract-style
82
+
83
+ Requires `--ref` (one to five images). **Authoritative procedure:
84
+ [references/style-extraction.md](references/style-extraction.md)** — read it first; it
85
+ owns the schema-fill rules, the multi-image merge rules, the cap-5 refusal wording,
86
+ where the preset is written (user root, shadowing by design), and the validation step:
87
+ read the images with your own vision, write `~/.config/kk/image-presets/styles/<name>.yaml`
88
+ filling exactly the `StylePreset` fields, then validate with a `KK_IMAGE_DRY_RUN=1` run
89
+ whose `style` is the new preset's name. Extraction never writes a `formats/*.yaml` —
90
+ a format is not recoverable from a picture.
91
+
92
+ ### list-presets
93
+
94
+ Enumerate the **real** preset roots the 0102 loader scans — builtin
95
+ (`plugins/generations/image-gen/presets/`), then `~/.config/kk/image-presets/`, then
96
+ `$KNOWLEDGE_KIT_PROJECT_ROOT/.kk/image-presets/`, then each `:`-separated
97
+ `KK_IMAGE_PRESET_PATH` entry — printing every format and style with its **origin
98
+ root**, plus (formats) `job`, `aspectRatio`, `defaultStyle`. Surface the loader's
99
+ diagnostics verbatim: `shadowed` names **both** paths (losing shipped file, winning
100
+ user file); `invalid` names the file and the schema violation. **Never read a shipped
101
+ markdown gallery** — no gallery exists; the roots are the one source of truth. This
102
+ output is also the text an unknown `--format`/`--style` refusal quotes.
103
+
104
+ ## Invocation contract
105
+
106
+ `$ARGUMENTS` (or the Skill call args) parse as:
107
+
108
+ ```
109
+ [prompt] [--format <name>] [--style <name>] [--var KEY=VALUE]... [--content <file>]
110
+ [--ref <path>]... [--count <n>] [--provider <name>] [--model <id>]
111
+ [--out <dir|file>] [--dry-run] [--list-presets] [--extract-style <name>]
112
+ ```
113
+
114
+ | Token | Meaning | Default |
115
+ | --- | --- | --- |
116
+ | `prompt` | free-form subject text | required for `free`; optional otherwise |
117
+ | `--format <name>` | format preset; its `job` field selects the branch | `image.format`, else `free` |
118
+ | `--style <name>` | style preset | format's `defaultStyle` |
119
+ | `--var KEY=VALUE` | template variable (repeatable) | preset `variables` defaults |
120
+ | `--content <file>` | markdown source for `cover` / `illustration` | none |
121
+ | `--ref <path>` | reference image (repeatable, **max 5**) | none |
122
+ | `--count <n>` | images to produce — **`illustration` job only** | number of `positions` anchors, else 1 |
123
+ | `--provider <name>` | 0103 provider name | auto (`AUTO_ORDER`) |
124
+ | `--model <id>` | provider model id | provider default |
125
+ | `--out <dir\|file>` | the plugin's `--out`; see Artifact contract | temp dir under the works dir |
126
+ | `--dry-run` | compose and price, generate nothing | off |
127
+ | `--list-presets` | → the `list-presets` operation | — |
128
+ | `--extract-style <name>` | → the `extract-style` operation; **requires `--ref`** | — |
129
+
130
+ **Validation is this skill's, before any plugin spawn**, each refusal naming the
131
+ offending argument: unknown `--format` or `--style` (quote what `list-presets` would
132
+ show); `--count` on a non-`illustration` job; more than five `--ref` paths;
133
+ `--extract-style` without `--ref`; a `--content` file that does not exist. Flags the
134
+ wt plugin retired are **answered, not ignored** — state the replacement and stop; the
135
+ table lives in
136
+ [references/migrating-from-wt.md](references/migrating-from-wt.md)
137
+ (`--template` → `--format`, `--resolution WxH` → the format's `aspectRatio`,
138
+ `--backend` → `--provider`, `--list-templates` → `--list-presets`).
139
+
140
+ ## Artifact contract
141
+
142
+ The skill writes exactly one input file — the `--in` JSON: a `Doc[]` whose **first
143
+ element** carries the whole job spec at `metadata.imageGen` (strict schema; a typo'd
144
+ key fails loud), plus `metadata.positions` for the illustration job:
145
+
146
+ ```json
147
+ [{
148
+ "id": "doc-1", "title": "Article title", "body": "<article text>",
149
+ "metadata": {
150
+ "imageGen": {
151
+ "job": "cover", "format": "cover", "style": "vibrant",
152
+ "provider": "seedream", "model": "doubao-seedream-5-0-260128",
153
+ "vars": { "title": "Article title", "subtitle": "Derived subtitle" },
154
+ "maxImages": 4, "outputStem": "article-title"
155
+ },
156
+ "positions": ["## A heading that occurs exactly once in the body"]
157
+ }
158
+ }]
159
+ ```
160
+
161
+ | Path | Rule |
162
+ | --- | --- |
163
+ | `--out` ending `.json` | used verbatim as the plugin's `--out` |
164
+ | `--out` anything else | treated as a directory; the plugin's `--out` becomes `<dir>/content.json` |
165
+ | generated images | **siblings** of `--out` (0104), named from the format's `outputFilename` |
166
+ | output `metadata.images[]` | one entry per image: absolute `path`, `format`, `style`, `provider`, `model`, the exact `prompt`, `bytes` |
167
+ | output `metadata.captions[]` | illustration only: `{index, path, caption, altText, anchor}` |
168
+
169
+ `metadata.imageGen` accepts only: `job`, `format`, `style`, `vars`, `extra`, `provider`,
170
+ `model`, `referenceImages`, `count`, `maxImages`, `seed`, `outputStem`. **No credential
171
+ is ever written into this file** — see Preference chain.
172
+
173
+ ## Preference chain
174
+
175
+ Every preference resolves through the repo's frozen order — **arguments >
176
+ environment > `$KK_CONFIG` > compiled defaults** — and the winners are written into
177
+ `metadata.imageGen`:
178
+
179
+ | Key | 1. argument | 2. environment | 3. `$KK_CONFIG` `image:` | 4. compiled default |
180
+ | --- | --- | --- | --- | --- |
181
+ | format | `--format` | — | `image.format` | `free` |
182
+ | style | `--style` | — | `image.style` | the format's `defaultStyle` |
183
+ | provider | `--provider` | `IMAGE_GEN_PROVIDER` | `image.provider` | auto (`AUTO_ORDER`) |
184
+ | model | `--model` | — | `image.model` | provider default |
185
+ | auto-confirm | — | `KK_IMAGE_AUTO_CONFIRM=1` | `image.auto_confirm` | `false` |
186
+ | max images | — | `KK_IMAGE_MAX_IMAGES` | `image.max_images` | `4` |
187
+ | preset roots | — | `KK_IMAGE_PRESET_PATH` | `image.preset_path` | none |
188
+
189
+ - `$KK_CONFIG` defaults to `~/.config/kk/config.yaml`. The environment **wins over the
190
+ config file**: an exported `KK_IMAGE_MAX_IMAGES` beats `image.max_images`.
191
+ - Loading is **non-blocking**: a missing or malformed `image:` block earns **one
192
+ notice line naming the block**, then the compiled defaults. Every key has a working
193
+ default; refusing to draw over a missing optional config is a worse failure than
194
+ drawing with defaults. (A malformed *preset* is a different matter and fails loud.)
195
+ - **No `EXTEND.md`** — do not read, create, or mention one: baoyu's ranks file above
196
+ environment, the opposite of this chain, and one product gets one precedence rule.
197
+ - **Credentials are not in this chain.** `plugins.generations.image-gen.env` values
198
+ reach the plugin only through `invoke.ts`'s process environment at spawn. They never
199
+ enter this skill's context, the `--in` file, or any report.
200
+
201
+ ## Confirmation policy
202
+
203
+ The skill is in exactly one of two contexts, signalled **explicitly**:
204
+ `KK_NONINTERACTIVE=1` means non-interactive. Never infer from a TTY probe — a wrong
205
+ guess is either a hang or an unapproved spend.
206
+
207
+ **Interactive** (default). Before any paid run: execute once with `KK_IMAGE_DRY_RUN=1`,
208
+ then present the **spend preview** — resolved format and style, provider and model,
209
+ image count, and the **composed prompt taken from that run's `Content.body`** (the real
210
+ string the provider will receive, not a reconstruction) — and ask **once** for
211
+ confirmation (`AskUserQuestion` where available). `--dry-run` stops here and reports.
212
+ Declining ends the run with no plugin spawn beyond the dry run. A modification request
213
+ re-runs the preview; the loop is bounded at **3 revision rounds**, after which state
214
+ the bound and ask the operator to restate the request — never a paid round.
215
+
216
+ **Non-interactive** (`KK_NONINTERACTIVE=1`, e.g. a `spur workflow` `agent.run` step).
217
+ **Never prompt — never emit a question.** Proceed only if `image.auto_confirm: true`
218
+ or `KK_IMAGE_AUTO_CONFIRM=1`; otherwise **fail immediately, naming both switches**.
219
+ Hanging is unrecoverable, and spending unapproved money is worse than a failed node.
220
+ A workflow node invoking this skill **must set `KK_NONINTERACTIVE=1`** (and choose its
221
+ auto-confirm switch) — that is the caller's contract.
222
+
223
+ The cap is the backstop under both paths: `maxImages` rides the envelope and the
224
+ plugin refuses before the first provider call (0104 R6). Confirmation is a courtesy;
225
+ the cap is the control.
226
+
227
+ ## Failure and recovery
228
+
229
+ - **Unknown format/style** — refuse, listing what `list-presets` shows.
230
+ - **Unimplemented `job` branch** — stop, naming the branch and format; never fall back
231
+ to `free`.
232
+ - **Malformed preset** — the 0102 loader's `invalid` diagnostic names the file and the
233
+ schema violation; the dry run fails loud before any spend. Fix or delete the file.
234
+ - **Provider cannot accept `--ref`** — when `supportsReferenceImages(model)` is false,
235
+ say so and offer `extract-style`; never silently drop a reference.
236
+ - **Declined confirmation** — end cleanly; only the dry run ran, nothing was spent.
237
+ - **Failed run** — the plugin deletes `--out` and every artefact of that run before
238
+ rethrowing; report the error verbatim and stop.
239
+ - **No credential anywhere** — name the provider and the env var it needs
240
+ (references/providers.md); never solicit a secret in chat.
241
+
242
+ ## References
243
+
244
+ - [references/style-extraction.md](references/style-extraction.md) — `extract-style` (0105): schema-fill rules, merge rules, cap, fidelity check.
245
+ - [references/illustration-positions.md](references/illustration-positions.md) —
246
+ position detection and caption authoring for `illustration`, with the wt example.
247
+ - [references/providers.md](references/providers.md) — the operator digest of 0103's
248
+ provider inventory: env vars, default models, reference capability, auto order.
249
+ - [references/migrating-from-wt.md](references/migrating-from-wt.md) — the retired wt
250
+ flags and their frozen replacements.
@@ -0,0 +1,87 @@
1
+ # Illustration positions and captions
2
+
3
+ Loaded by the image-authoring skill when the resolved format's `job` is
4
+ `illustration`. Position detection, concept prompts and caption authoring are
5
+ **model work** — this file's — while the plugin does the deterministic half:
6
+ composing one prompt per anchor (the anchor rides the format's `concept`
7
+ template variable), generating, and inserting the markdown at the anchor. The
8
+ skill's entire output across this boundary is `metadata.positions` in the
9
+ `--in` envelope.
10
+
11
+ ## The anchor contract
12
+
13
+ - `metadata.positions` is an **array of anchor strings**, one per illustration.
14
+ - Each anchor must occur **exactly once** in the doc `body` — the plugin
15
+ inserts at that occurrence and fails loud if it is absent or ambiguous.
16
+ Headings and distinctive sentences are safe anchors; short common phrases
17
+ are not.
18
+ - The array length is the image count: `--count` must equal it, and each
19
+ anchor is fed as image *i*'s `concept` var (`plugins/generations/image-gen/src/index.ts`
20
+ composes one prompt per anchor in array order).
21
+ - The budget still applies: the default cap is 4 images (`maxImages`); a
22
+ longer article does not silently spend past it.
23
+
24
+ ## Detection procedure
25
+
26
+ Read the article once, end to end, then list **candidate** positions before
27
+ selecting. For each candidate record: line/section, **type**, a 0–12 **score**,
28
+ and a one-line rationale. The wt taxonomy, kept because it works:
29
+
30
+ | Type | Looks like | Typical score driver |
31
+ | --- | --- | --- |
32
+ | abstract concept | jargon-dense section with no visual ("microservices architecture", "service discovery") | technical-jargon density |
33
+ | information dense | wide tables, long parameter lists | structure that a diagram would organise |
34
+ | emotional transition | major section break, shift in narrative register | flow improvement |
35
+
36
+ Selection rules (the wt defaults, kept): prefer higher score; keep at least
37
+ ~20 lines between chosen positions; respect the operator's `--count` as the
38
+ maximum; spread across types rather than clustering on one. Fewer, better
39
+ placements beat filling the quota.
40
+
41
+ For each **selected** position, author in the same pass:
42
+
43
+ 1. **Anchor** — the exactly-once string from the body.
44
+ 2. **Concept** — a one-sentence visual brief; the plugin feeds it to the
45
+ format's `concept` variable, so write it as an image subject, not prose
46
+ about the article.
47
+ 3. **Caption and alt text** — the caption states what the image adds; the alt
48
+ text describes the image for a screen reader (complete sentence, no "image
49
+ of"). These are reported to the operator against each artefact path.
50
+ 4. **Style** — default to the resolved style; `technical-diagram` suits
51
+ concepts and dense reference content, `sketch` suits data relationships,
52
+ `minimalist` suits transitions. A proposal, shown in the preview — the
53
+ operator confirms the whole spend once.
54
+
55
+ ## Worked example (from the wt plugin, the prior art)
56
+
57
+ Input: `article-before.md`, a 1,850-word microservices guide with no images.
58
+ Detection found **8 candidates, selected 5** (two dropped for sitting too
59
+ close to a higher-scoring neighbour, one for low score):
60
+
61
+ | # | Line | Type | Score | Selected |
62
+ | --- | --- | --- | --- | --- |
63
+ | 1 | 23 | abstract concept ("What Are Microservices?") | 12 | yes |
64
+ | 2 | 45 | abstract concept (service discovery) | 11 | yes |
65
+ | 3 | 62 | information dense (7-column API table) | 10 | yes |
66
+ | 4 | 79 | abstract concept (communication patterns) | 10 | no — too close to #3 |
67
+ | 5 | 92 | information dense (configuration list) | 11 | yes |
68
+ | 6 | 112 | emotional transition ("Best Practices") | 7 | yes |
69
+ | 7 | 128 | abstract concept | 8 | no — below the line |
70
+
71
+ The chosen anchors became `metadata.positions`; image *i*'s anchor was fed as
72
+ its `concept` — e.g. position 1's concept, "Microservices architecture pattern
73
+ with API gateway", produced a technical-diagram prompt, and the caption
74
+ reported back as alt text: "Diagram showing microservices architecture with
75
+ API gateway, independent services with databases, and message queue
76
+ communication". The output side is `article-after.md` — the same article with
77
+ `![alt](path)` references at the anchors — plus the captions payload the
78
+ plugin emits at `metadata.captions[]` (`{index, path, caption, altText,
79
+ anchor}`), which is what the skill reports to the operator.
80
+
81
+ ## What this file never does
82
+
83
+ - No detection inside the plugin — the plugin never reads for meaning; it
84
+ only inserts where told.
85
+ - No image selection after the fact — positions are decided **before** the
86
+ confirmation preview, so the operator approves the whole spend knowingly.
87
+ - No caption writing inside the plugin — captions are the skill's voice.
@@ -0,0 +1,31 @@
1
+ # Migrating from the wt image commands
2
+
3
+ For operators arriving from the `wt` plugin (`/wt:image-generate` and its
4
+ three skills). The kk surface is **one command** (`/kk:image-generate`)
5
+ driving **one skill** (`kk:image-authoring`). Flag by flag:
6
+
7
+ | wt flag | kk replacement | Why |
8
+ | --- | --- | --- |
9
+ | `--template <name>` | `--format <name>` | Templates are formats now — data presets (0102). wt's `default` → `free`; `cover` → `cover`; `illustrator` → `illustration`. A custom template like `cover-xhs` becomes a YAML file in `~/.config/kk/image-presets/formats/` — no skill or plugin edit needed. |
10
+ | `--resolution WxH` | *(dropped)* | The format's `aspectRatio` owns dimensions (0102 R1) — a portable ratio beats per-call pixels across twelve providers. A different shape means a different or overridden format. |
11
+ | `--backend <name>` | `--provider <name>` | 0103's inventory replaces wt's three backends: `gemini` → `google`; `nano_banana` → `replicate`; `huggingface` has no kk equivalent. Omitting `--provider` auto-selects (see providers.md). |
12
+ | `--list-templates` | `--list-presets` | Lists formats **and** styles from the real preset roots, with origin and shadowing diagnostics. |
13
+ | `--output <path>` | `--out <dir\|file>` | A path ending `.json` is used verbatim; anything else is a directory, and generated images land as its siblings. |
14
+
15
+ Kept, unchanged in meaning: the positional prompt, `--style`,
16
+ `--var KEY=VALUE`, `--content <file>`.
17
+
18
+ Also different, by design:
19
+
20
+ - The command validates nothing — the skill does. Thinner command, same
21
+ refusals, one place that knows the rules.
22
+ - The three wt skills' model work (content analysis, style auto-detection,
23
+ position detection) lives inside this one skill as named capabilities, not
24
+ three skills.
25
+ - The `wt:image-generator` coordinator subagent is deliberately **not
26
+ ported** — a forwarder over a single skill is an indirection with nothing
27
+ in it.
28
+ - Spend control: kk previews the real prompt via a `KK_IMAGE_DRY_RUN=1` run
29
+ and asks once before the paid run; workflow nodes must set
30
+ `KK_NONINTERACTIVE=1`. The wt `--resolution`-style per-call budget has no
31
+ equivalent — `maxImages` (env/config) is the cap.
@@ -0,0 +1,52 @@
1
+ # Provider facts for image generation
2
+
3
+ The operator-facing digest of 0103's provider inventory. Source of truth:
4
+ `plugins/generations/image-gen/src/providers/types.ts` (the frozen registry) —
5
+ if this file and the registry ever disagree, the registry wins and this file
6
+ gets fixed. Credential *values* live only in
7
+ `plugins.generations.image-gen.env` (`plugins/kk/config.example.yaml`); they
8
+ are read by `invoke.ts` at spawn, never by this skill.
9
+
10
+ ## The rules
11
+
12
+ - **Readiness is env presence.** A provider is available when its env var(s)
13
+ are non-empty. A stale key still passes readiness and surfaces as the
14
+ adapter's own auth error at generate time.
15
+ - **Auto-selection** walks `AUTO_ORDER` — google, openai, replicate,
16
+ openrouter, dashscope, seedream, zai, minimax, jimeng, azure, agnes — and
17
+ takes the first available. `IMAGE_GEN_PROVIDER` names a provider explicitly;
18
+ `--provider` outranks it.
19
+ - **`codex-cli` is never auto-selected.** Its readiness (the `codex` CLI on
20
+ PATH with an active login) is not env-expressible; pin it explicitly.
21
+ - **Reference images** ride `--ref` only when `supportsReferenceImages(model)`
22
+ is true for the resolved model — a substring test over the registry's
23
+ `refModels` fragments (no `refModels` = every model; empty list = none).
24
+ When it is false, say so and offer `extract-style`; never drop the
25
+ reference silently.
26
+
27
+ ## The inventory
28
+
29
+ | Provider | Env var(s) that enable it | Default model | Reference images |
30
+ | --- | --- | --- | --- |
31
+ | agnes | `AGNES_API_KEY` | `agnes-image-2.1-flash` | yes |
32
+ | azure | `AZURE_OPENAI_API_KEY` (+ `AZURE_OPENAI_BASE_URL`, `AZURE_OPENAI_DEPLOYMENT` to run) | `gpt-image-2` | yes (no `refModels` declared → every model passes `supportsReferenceImages`) |
33
+ | codex-cli | not env-expressible — `codex` CLI + login | `codex-image-gen` | never auto-selected |
34
+ | dashscope | `DASHSCOPE_API_KEY` | `qwen-image-2.0-pro` | only `wan2.7` models |
35
+ | google | `GOOGLE_API_KEY` or `GEMINI_API_KEY` | `gemini-3-pro-image` | the gemini image models (`gemini-3-pro-image`, `*-flash-image`, previews) |
36
+ | jimeng | `JIMENG_ACCESS_KEY_ID` **and** `JIMENG_SECRET_ACCESS_KEY` (both halves) | `jimeng_t2i_v40` | yes |
37
+ | minimax | `MINIMAX_API_KEY` | `image-01` | yes (jpg/png <10MB, subject reference) |
38
+ | openai | `OPENAI_API_KEY` | `gpt-image-2` | `gpt-image` models |
39
+ | openrouter | `OPENROUTER_API_KEY` | `google/gemini-3.1-flash-image` | yes (no `refModels` declared → treated as supporting; real capability depends on the routed model) |
40
+ | replicate | `REPLICATE_API_TOKEN` | `google/nano-banana-2` | yes |
41
+ | seedream | `ARK_API_KEY` (not `SEEDREAM_*`) | `doubao-seedream-5-0-260128` | `doubao-seedream-5-0` / `4-5-` / `4-0-` models |
42
+ | zai | `ZAI_API_KEY` or `BIGMODEL_API_KEY` | `glm-image` | **none** |
43
+
44
+ ## Deciding with references in hand
45
+
46
+ 1. Resolve the provider per Preference chain (argument → `IMAGE_GEN_PROVIDER`
47
+ → config → `AUTO_ORDER`).
48
+ 2. Check `supportsReferenceImages` for the resolved model. False → the
49
+ pass-through path is unavailable: state it and offer style extraction
50
+ (0105), which works with every provider.
51
+ 3. Name the chosen provider and model in the spend preview — the operator
52
+ approves the pair, not just the prompt.