0xkobold 0.0.1

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 (258) hide show
  1. package/.agents/skills/nextjs-best-practices/SKILL.md +208 -0
  2. package/.agents/skills/sql-optimization-patterns/SKILL.md +509 -0
  3. package/HEARTBEAT.md +45 -0
  4. package/README.md +197 -0
  5. package/USAGE.md +191 -0
  6. package/dist/package.json +77 -0
  7. package/dist/src/agent/pi-adapter.js +307 -0
  8. package/dist/src/agent/pi-adapter.js.map +1 -0
  9. package/dist/src/agent/tool-adapter.js +86 -0
  10. package/dist/src/agent/tool-adapter.js.map +1 -0
  11. package/dist/src/approval/queue.js +114 -0
  12. package/dist/src/approval/queue.js.map +1 -0
  13. package/dist/src/ascii-kobold.js +76 -0
  14. package/dist/src/ascii-kobold.js.map +1 -0
  15. package/dist/src/cli/client.js +217 -0
  16. package/dist/src/cli/client.js.map +1 -0
  17. package/dist/src/cli/commands/agent.js +272 -0
  18. package/dist/src/cli/commands/agent.js.map +1 -0
  19. package/dist/src/cli/commands/chat.js +234 -0
  20. package/dist/src/cli/commands/chat.js.map +1 -0
  21. package/dist/src/cli/commands/config.js +202 -0
  22. package/dist/src/cli/commands/config.js.map +1 -0
  23. package/dist/src/cli/commands/daemon.js +203 -0
  24. package/dist/src/cli/commands/daemon.js.map +1 -0
  25. package/dist/src/cli/commands/gateway.js +184 -0
  26. package/dist/src/cli/commands/gateway.js.map +1 -0
  27. package/dist/src/cli/commands/init.js +175 -0
  28. package/dist/src/cli/commands/init.js.map +1 -0
  29. package/dist/src/cli/commands/kobold.js +21 -0
  30. package/dist/src/cli/commands/kobold.js.map +1 -0
  31. package/dist/src/cli/commands/logs.js +27 -0
  32. package/dist/src/cli/commands/logs.js.map +1 -0
  33. package/dist/src/cli/commands/mode.js +121 -0
  34. package/dist/src/cli/commands/mode.js.map +1 -0
  35. package/dist/src/cli/commands/persona.js +261 -0
  36. package/dist/src/cli/commands/persona.js.map +1 -0
  37. package/dist/src/cli/commands/start.js +66 -0
  38. package/dist/src/cli/commands/start.js.map +1 -0
  39. package/dist/src/cli/commands/status.js +117 -0
  40. package/dist/src/cli/commands/status.js.map +1 -0
  41. package/dist/src/cli/commands/stop.js +27 -0
  42. package/dist/src/cli/commands/stop.js.map +1 -0
  43. package/dist/src/cli/commands/system.js +128 -0
  44. package/dist/src/cli/commands/system.js.map +1 -0
  45. package/dist/src/cli/commands/tui.js +103 -0
  46. package/dist/src/cli/commands/tui.js.map +1 -0
  47. package/dist/src/cli/commands/update.js +133 -0
  48. package/dist/src/cli/commands/update.js.map +1 -0
  49. package/dist/src/cli/extensions/discord.js +113 -0
  50. package/dist/src/cli/extensions/discord.js.map +1 -0
  51. package/dist/src/cli/extensions/env.js +91 -0
  52. package/dist/src/cli/extensions/env.js.map +1 -0
  53. package/dist/src/cli/extensions/heartbeat.js +78 -0
  54. package/dist/src/cli/extensions/heartbeat.js.map +1 -0
  55. package/dist/src/cli/index.js +24 -0
  56. package/dist/src/cli/index.js.map +1 -0
  57. package/dist/src/cli/program.js +70 -0
  58. package/dist/src/cli/program.js.map +1 -0
  59. package/dist/src/cli/repl.js +184 -0
  60. package/dist/src/cli/repl.js.map +1 -0
  61. package/dist/src/cli/shared/discord-service.js +102 -0
  62. package/dist/src/cli/shared/discord-service.js.map +1 -0
  63. package/dist/src/config/index.js +10 -0
  64. package/dist/src/config/index.js.map +1 -0
  65. package/dist/src/config/loader.js +401 -0
  66. package/dist/src/config/loader.js.map +1 -0
  67. package/dist/src/config/paths.js +84 -0
  68. package/dist/src/config/paths.js.map +1 -0
  69. package/dist/src/config/types.js +8 -0
  70. package/dist/src/config/types.js.map +1 -0
  71. package/dist/src/context-detector.js +60 -0
  72. package/dist/src/context-detector.js.map +1 -0
  73. package/dist/src/discord/index.js +376 -0
  74. package/dist/src/discord/index.js.map +1 -0
  75. package/dist/src/event-bus/index.js +97 -0
  76. package/dist/src/event-bus/index.js.map +1 -0
  77. package/dist/src/extensions/command-args.js +68 -0
  78. package/dist/src/extensions/command-args.js.map +1 -0
  79. package/dist/src/extensions/core/agent-registry-extension.js +541 -0
  80. package/dist/src/extensions/core/agent-registry-extension.js.map +1 -0
  81. package/dist/src/extensions/core/agent-worker.js +148 -0
  82. package/dist/src/extensions/core/agent-worker.js.map +1 -0
  83. package/dist/src/extensions/core/compaction-safeguard.js +154 -0
  84. package/dist/src/extensions/core/compaction-safeguard.js.map +1 -0
  85. package/dist/src/extensions/core/confirm-destructive.js +43 -0
  86. package/dist/src/extensions/core/confirm-destructive.js.map +1 -0
  87. package/dist/src/extensions/core/context-aware-extension.js +124 -0
  88. package/dist/src/extensions/core/context-aware-extension.js.map +1 -0
  89. package/dist/src/extensions/core/context-pruning/extension.js +124 -0
  90. package/dist/src/extensions/core/context-pruning/extension.js.map +1 -0
  91. package/dist/src/extensions/core/context-pruning/pruner.js +312 -0
  92. package/dist/src/extensions/core/context-pruning/pruner.js.map +1 -0
  93. package/dist/src/extensions/core/context-pruning/runtime.js +48 -0
  94. package/dist/src/extensions/core/context-pruning/runtime.js.map +1 -0
  95. package/dist/src/extensions/core/context-pruning/settings.js +105 -0
  96. package/dist/src/extensions/core/context-pruning/settings.js.map +1 -0
  97. package/dist/src/extensions/core/dirty-repo-guard.js +42 -0
  98. package/dist/src/extensions/core/dirty-repo-guard.js.map +1 -0
  99. package/dist/src/extensions/core/discord-channel-extension.js +205 -0
  100. package/dist/src/extensions/core/discord-channel-extension.js.map +1 -0
  101. package/dist/src/extensions/core/discord-extension.js +142 -0
  102. package/dist/src/extensions/core/discord-extension.js.map +1 -0
  103. package/dist/src/extensions/core/env-loader-extension.js +157 -0
  104. package/dist/src/extensions/core/env-loader-extension.js.map +1 -0
  105. package/dist/src/extensions/core/fileops-extension.js +699 -0
  106. package/dist/src/extensions/core/fileops-extension.js.map +1 -0
  107. package/dist/src/extensions/core/gateway-extension.js +730 -0
  108. package/dist/src/extensions/core/gateway-extension.js.map +1 -0
  109. package/dist/src/extensions/core/git-checkpoint.js +46 -0
  110. package/dist/src/extensions/core/git-checkpoint.js.map +1 -0
  111. package/dist/src/extensions/core/handoff-extension.js +206 -0
  112. package/dist/src/extensions/core/handoff-extension.js.map +1 -0
  113. package/dist/src/extensions/core/heartbeat-extension.js +373 -0
  114. package/dist/src/extensions/core/heartbeat-extension.js.map +1 -0
  115. package/dist/src/extensions/core/mcp-extension.js +413 -0
  116. package/dist/src/extensions/core/mcp-extension.js.map +1 -0
  117. package/dist/src/extensions/core/mode-manager-extension.js +562 -0
  118. package/dist/src/extensions/core/mode-manager-extension.js.map +1 -0
  119. package/dist/src/extensions/core/multi-channel-extension.js +435 -0
  120. package/dist/src/extensions/core/multi-channel-extension.js.map +1 -0
  121. package/dist/src/extensions/core/ollama-provider-extension.js +66 -0
  122. package/dist/src/extensions/core/ollama-provider-extension.js.map +1 -0
  123. package/dist/src/extensions/core/onboarding-extension.js +122 -0
  124. package/dist/src/extensions/core/onboarding-extension.js.map +1 -0
  125. package/dist/src/extensions/core/persona-loader-extension.js +139 -0
  126. package/dist/src/extensions/core/persona-loader-extension.js.map +1 -0
  127. package/dist/src/extensions/core/pi-notify-extension.js +70 -0
  128. package/dist/src/extensions/core/pi-notify-extension.js.map +1 -0
  129. package/dist/src/extensions/core/protected-paths.js +24 -0
  130. package/dist/src/extensions/core/protected-paths.js.map +1 -0
  131. package/dist/src/extensions/core/questionnaire-extension.js +242 -0
  132. package/dist/src/extensions/core/questionnaire-extension.js.map +1 -0
  133. package/dist/src/extensions/core/self-update-extension.js +181 -0
  134. package/dist/src/extensions/core/self-update-extension.js.map +1 -0
  135. package/dist/src/extensions/core/session-bridge-extension.js +78 -0
  136. package/dist/src/extensions/core/session-bridge-extension.js.map +1 -0
  137. package/dist/src/extensions/core/session-manager-extension.js +319 -0
  138. package/dist/src/extensions/core/session-manager-extension.js.map +1 -0
  139. package/dist/src/extensions/core/session-name-extension.js +88 -0
  140. package/dist/src/extensions/core/session-name-extension.js.map +1 -0
  141. package/dist/src/extensions/core/session-pruning-extension.js +480 -0
  142. package/dist/src/extensions/core/session-pruning-extension.js.map +1 -0
  143. package/dist/src/extensions/core/task-manager-extension.js +661 -0
  144. package/dist/src/extensions/core/task-manager-extension.js.map +1 -0
  145. package/dist/src/extensions/core/update-extension.js +438 -0
  146. package/dist/src/extensions/core/update-extension.js.map +1 -0
  147. package/dist/src/extensions/core/websearch-extension.js +463 -0
  148. package/dist/src/extensions/core/websearch-extension.js.map +1 -0
  149. package/dist/src/extensions/index.js +5 -0
  150. package/dist/src/extensions/index.js.map +1 -0
  151. package/dist/src/extensions/loader.js +80 -0
  152. package/dist/src/extensions/loader.js.map +1 -0
  153. package/dist/src/gateway/index.js +353 -0
  154. package/dist/src/gateway/index.js.map +1 -0
  155. package/dist/src/index.js +150 -0
  156. package/dist/src/index.js.map +1 -0
  157. package/dist/src/llm/anthropic.js +86 -0
  158. package/dist/src/llm/anthropic.js.map +1 -0
  159. package/dist/src/llm/index.js +9 -0
  160. package/dist/src/llm/index.js.map +1 -0
  161. package/dist/src/llm/ollama.js +113 -0
  162. package/dist/src/llm/ollama.js.map +1 -0
  163. package/dist/src/llm/router.js +145 -0
  164. package/dist/src/llm/router.js.map +1 -0
  165. package/dist/src/llm/types.js +7 -0
  166. package/dist/src/llm/types.js.map +1 -0
  167. package/dist/src/memory/index.js +5 -0
  168. package/dist/src/memory/index.js.map +1 -0
  169. package/dist/src/memory/store.js +91 -0
  170. package/dist/src/memory/store.js.map +1 -0
  171. package/dist/src/pi-config.js +80 -0
  172. package/dist/src/pi-config.js.map +1 -0
  173. package/dist/src/skills/builtin/file.js +184 -0
  174. package/dist/src/skills/builtin/file.js.map +1 -0
  175. package/dist/src/skills/builtin/shell.js +100 -0
  176. package/dist/src/skills/builtin/shell.js.map +1 -0
  177. package/dist/src/skills/builtin/subagent.js +62 -0
  178. package/dist/src/skills/builtin/subagent.js.map +1 -0
  179. package/dist/src/skills/hello.js +42 -0
  180. package/dist/src/skills/hello.js.map +1 -0
  181. package/dist/src/skills/index.js +11 -0
  182. package/dist/src/skills/index.js.map +1 -0
  183. package/dist/src/skills/loader.js +382 -0
  184. package/dist/src/skills/loader.js.map +1 -0
  185. package/dist/src/skills/types.js +8 -0
  186. package/dist/src/skills/types.js.map +1 -0
  187. package/dist/src/utils/working-dir.js +71 -0
  188. package/dist/src/utils/working-dir.js.map +1 -0
  189. package/package.json +77 -0
  190. package/skills/1password/SKILL.md +70 -0
  191. package/skills/1password/references/cli-examples.md +29 -0
  192. package/skills/1password/references/get-started.md +17 -0
  193. package/skills/apple-notes/SKILL.md +77 -0
  194. package/skills/apple-reminders/SKILL.md +118 -0
  195. package/skills/bear-notes/SKILL.md +107 -0
  196. package/skills/blogwatcher/SKILL.md +69 -0
  197. package/skills/blucli/SKILL.md +47 -0
  198. package/skills/bluebubbles/SKILL.md +131 -0
  199. package/skills/camsnap/SKILL.md +45 -0
  200. package/skills/canvas/SKILL.md +198 -0
  201. package/skills/clawhub/SKILL.md +77 -0
  202. package/skills/coding-agent/SKILL.md +284 -0
  203. package/skills/discord/SKILL.md +197 -0
  204. package/skills/eightctl/SKILL.md +50 -0
  205. package/skills/food-order/SKILL.md +48 -0
  206. package/skills/gemini/SKILL.md +43 -0
  207. package/skills/gh-issues/SKILL.md +865 -0
  208. package/skills/gifgrep/SKILL.md +79 -0
  209. package/skills/github/SKILL.md +163 -0
  210. package/skills/gog/SKILL.md +116 -0
  211. package/skills/goplaces/SKILL.md +52 -0
  212. package/skills/healthcheck/SKILL.md +245 -0
  213. package/skills/himalaya/SKILL.md +257 -0
  214. package/skills/himalaya/references/configuration.md +184 -0
  215. package/skills/himalaya/references/message-composition.md +199 -0
  216. package/skills/imsg/SKILL.md +122 -0
  217. package/skills/mcporter/SKILL.md +61 -0
  218. package/skills/model-usage/SKILL.md +69 -0
  219. package/skills/model-usage/references/codexbar-cli.md +33 -0
  220. package/skills/model-usage/scripts/model_usage.py +310 -0
  221. package/skills/nano-banana-pro/SKILL.md +58 -0
  222. package/skills/nano-banana-pro/scripts/generate_image.py +184 -0
  223. package/skills/nano-pdf/SKILL.md +38 -0
  224. package/skills/notion/SKILL.md +172 -0
  225. package/skills/obsidian/SKILL.md +81 -0
  226. package/skills/openai-image-gen/SKILL.md +89 -0
  227. package/skills/openai-image-gen/scripts/gen.py +240 -0
  228. package/skills/openai-whisper/SKILL.md +38 -0
  229. package/skills/openai-whisper-api/SKILL.md +52 -0
  230. package/skills/openai-whisper-api/scripts/transcribe.sh +85 -0
  231. package/skills/openhue/SKILL.md +112 -0
  232. package/skills/oracle/SKILL.md +125 -0
  233. package/skills/ordercli/SKILL.md +78 -0
  234. package/skills/peekaboo/SKILL.md +190 -0
  235. package/skills/sag/SKILL.md +87 -0
  236. package/skills/session-logs/SKILL.md +115 -0
  237. package/skills/sherpa-onnx-tts/SKILL.md +103 -0
  238. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  239. package/skills/skill-creator/SKILL.md +370 -0
  240. package/skills/skill-creator/license.txt +202 -0
  241. package/skills/skill-creator/scripts/init_skill.py +378 -0
  242. package/skills/skill-creator/scripts/package_skill.py +111 -0
  243. package/skills/skill-creator/scripts/quick_validate.py +101 -0
  244. package/skills/slack/SKILL.md +144 -0
  245. package/skills/songsee/SKILL.md +49 -0
  246. package/skills/sonoscli/SKILL.md +46 -0
  247. package/skills/spotify-player/SKILL.md +64 -0
  248. package/skills/summarize/SKILL.md +87 -0
  249. package/skills/things-mac/SKILL.md +86 -0
  250. package/skills/tmux/SKILL.md +153 -0
  251. package/skills/tmux/scripts/find-sessions.sh +112 -0
  252. package/skills/tmux/scripts/wait-for-text.sh +83 -0
  253. package/skills/trello/SKILL.md +95 -0
  254. package/skills/video-frames/SKILL.md +46 -0
  255. package/skills/video-frames/scripts/frame.sh +81 -0
  256. package/skills/voice-call/SKILL.md +45 -0
  257. package/skills/wacli/SKILL.md +72 -0
  258. package/skills/weather/SKILL.md +112 -0
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env python3
2
+ # /// script
3
+ # requires-python = ">=3.10"
4
+ # dependencies = [
5
+ # "google-genai>=1.0.0",
6
+ # "pillow>=10.0.0",
7
+ # ]
8
+ # ///
9
+ """
10
+ Generate images using Google's Nano Banana Pro (Gemini 3 Pro Image) API.
11
+
12
+ Usage:
13
+ uv run generate_image.py --prompt "your image description" --filename "output.png" [--resolution 1K|2K|4K] [--api-key KEY]
14
+
15
+ Multi-image editing (up to 14 images):
16
+ uv run generate_image.py --prompt "combine these images" --filename "output.png" -i img1.png -i img2.png -i img3.png
17
+ """
18
+
19
+ import argparse
20
+ import os
21
+ import sys
22
+ from pathlib import Path
23
+
24
+
25
+ def get_api_key(provided_key: str | None) -> str | None:
26
+ """Get API key from argument first, then environment."""
27
+ if provided_key:
28
+ return provided_key
29
+ return os.environ.get("GEMINI_API_KEY")
30
+
31
+
32
+ def main():
33
+ parser = argparse.ArgumentParser(
34
+ description="Generate images using Nano Banana Pro (Gemini 3 Pro Image)"
35
+ )
36
+ parser.add_argument(
37
+ "--prompt", "-p",
38
+ required=True,
39
+ help="Image description/prompt"
40
+ )
41
+ parser.add_argument(
42
+ "--filename", "-f",
43
+ required=True,
44
+ help="Output filename (e.g., sunset-mountains.png)"
45
+ )
46
+ parser.add_argument(
47
+ "--input-image", "-i",
48
+ action="append",
49
+ dest="input_images",
50
+ metavar="IMAGE",
51
+ help="Input image path(s) for editing/composition. Can be specified multiple times (up to 14 images)."
52
+ )
53
+ parser.add_argument(
54
+ "--resolution", "-r",
55
+ choices=["1K", "2K", "4K"],
56
+ default="1K",
57
+ help="Output resolution: 1K (default), 2K, or 4K"
58
+ )
59
+ parser.add_argument(
60
+ "--api-key", "-k",
61
+ help="Gemini API key (overrides GEMINI_API_KEY env var)"
62
+ )
63
+
64
+ args = parser.parse_args()
65
+
66
+ # Get API key
67
+ api_key = get_api_key(args.api_key)
68
+ if not api_key:
69
+ print("Error: No API key provided.", file=sys.stderr)
70
+ print("Please either:", file=sys.stderr)
71
+ print(" 1. Provide --api-key argument", file=sys.stderr)
72
+ print(" 2. Set GEMINI_API_KEY environment variable", file=sys.stderr)
73
+ sys.exit(1)
74
+
75
+ # Import here after checking API key to avoid slow import on error
76
+ from google import genai
77
+ from google.genai import types
78
+ from PIL import Image as PILImage
79
+
80
+ # Initialise client
81
+ client = genai.Client(api_key=api_key)
82
+
83
+ # Set up output path
84
+ output_path = Path(args.filename)
85
+ output_path.parent.mkdir(parents=True, exist_ok=True)
86
+
87
+ # Load input images if provided (up to 14 supported by Nano Banana Pro)
88
+ input_images = []
89
+ output_resolution = args.resolution
90
+ if args.input_images:
91
+ if len(args.input_images) > 14:
92
+ print(f"Error: Too many input images ({len(args.input_images)}). Maximum is 14.", file=sys.stderr)
93
+ sys.exit(1)
94
+
95
+ max_input_dim = 0
96
+ for img_path in args.input_images:
97
+ try:
98
+ img = PILImage.open(img_path)
99
+ input_images.append(img)
100
+ print(f"Loaded input image: {img_path}")
101
+
102
+ # Track largest dimension for auto-resolution
103
+ width, height = img.size
104
+ max_input_dim = max(max_input_dim, width, height)
105
+ except Exception as e:
106
+ print(f"Error loading input image '{img_path}': {e}", file=sys.stderr)
107
+ sys.exit(1)
108
+
109
+ # Auto-detect resolution from largest input if not explicitly set
110
+ if args.resolution == "1K" and max_input_dim > 0: # Default value
111
+ if max_input_dim >= 3000:
112
+ output_resolution = "4K"
113
+ elif max_input_dim >= 1500:
114
+ output_resolution = "2K"
115
+ else:
116
+ output_resolution = "1K"
117
+ print(f"Auto-detected resolution: {output_resolution} (from max input dimension {max_input_dim})")
118
+
119
+ # Build contents (images first if editing, prompt only if generating)
120
+ if input_images:
121
+ contents = [*input_images, args.prompt]
122
+ img_count = len(input_images)
123
+ print(f"Processing {img_count} image{'s' if img_count > 1 else ''} with resolution {output_resolution}...")
124
+ else:
125
+ contents = args.prompt
126
+ print(f"Generating image with resolution {output_resolution}...")
127
+
128
+ try:
129
+ response = client.models.generate_content(
130
+ model="gemini-3-pro-image-preview",
131
+ contents=contents,
132
+ config=types.GenerateContentConfig(
133
+ response_modalities=["TEXT", "IMAGE"],
134
+ image_config=types.ImageConfig(
135
+ image_size=output_resolution
136
+ )
137
+ )
138
+ )
139
+
140
+ # Process response and convert to PNG
141
+ image_saved = False
142
+ for part in response.parts:
143
+ if part.text is not None:
144
+ print(f"Model response: {part.text}")
145
+ elif part.inline_data is not None:
146
+ # Convert inline data to PIL Image and save as PNG
147
+ from io import BytesIO
148
+
149
+ # inline_data.data is already bytes, not base64
150
+ image_data = part.inline_data.data
151
+ if isinstance(image_data, str):
152
+ # If it's a string, it might be base64
153
+ import base64
154
+ image_data = base64.b64decode(image_data)
155
+
156
+ image = PILImage.open(BytesIO(image_data))
157
+
158
+ # Ensure RGB mode for PNG (convert RGBA to RGB with white background if needed)
159
+ if image.mode == 'RGBA':
160
+ rgb_image = PILImage.new('RGB', image.size, (255, 255, 255))
161
+ rgb_image.paste(image, mask=image.split()[3])
162
+ rgb_image.save(str(output_path), 'PNG')
163
+ elif image.mode == 'RGB':
164
+ image.save(str(output_path), 'PNG')
165
+ else:
166
+ image.convert('RGB').save(str(output_path), 'PNG')
167
+ image_saved = True
168
+
169
+ if image_saved:
170
+ full_path = output_path.resolve()
171
+ print(f"\nImage saved: {full_path}")
172
+ # Kobold parses MEDIA tokens and will attach the file on supported providers.
173
+ print(f"MEDIA: {full_path}")
174
+ else:
175
+ print("Error: No image was generated in the response.", file=sys.stderr)
176
+ sys.exit(1)
177
+
178
+ except Exception as e:
179
+ print(f"Error generating image: {e}", file=sys.stderr)
180
+ sys.exit(1)
181
+
182
+
183
+ if __name__ == "__main__":
184
+ main()
@@ -0,0 +1,38 @@
1
+ ---
2
+ name: nano-pdf
3
+ description: Edit PDFs with natural-language instructions using the nano-pdf CLI.
4
+ homepage: https://pypi.org/project/nano-pdf/
5
+ metadata:
6
+ {
7
+ "kobold":
8
+ {
9
+ "emoji": "📄",
10
+ "requires": { "bins": ["nano-pdf"] },
11
+ "install":
12
+ [
13
+ {
14
+ "id": "uv",
15
+ "kind": "uv",
16
+ "package": "nano-pdf",
17
+ "bins": ["nano-pdf"],
18
+ "label": "Install nano-pdf (uv)",
19
+ },
20
+ ],
21
+ },
22
+ }
23
+ ---
24
+
25
+ # nano-pdf
26
+
27
+ Use `nano-pdf` to apply edits to a specific page in a PDF using a natural-language instruction.
28
+
29
+ ## Quick start
30
+
31
+ ```bash
32
+ nano-pdf edit deck.pdf 1 "Change the title to 'Q3 Results' and fix the typo in the subtitle"
33
+ ```
34
+
35
+ Notes:
36
+
37
+ - Page numbers are 0-based or 1-based depending on the tool’s version/config; if the result looks off by one, retry with the other.
38
+ - Always sanity-check the output PDF before sending it out.
@@ -0,0 +1,172 @@
1
+ ---
2
+ name: notion
3
+ description: Notion API for creating and managing pages, databases, and blocks.
4
+ homepage: https://developers.notion.com
5
+ metadata:
6
+ {
7
+ "kobold":
8
+ { "emoji": "📝", "requires": { "env": ["NOTION_API_KEY"] }, "primaryEnv": "NOTION_API_KEY" },
9
+ }
10
+ ---
11
+
12
+ # notion
13
+
14
+ Use the Notion API to create/read/update pages, data sources (databases), and blocks.
15
+
16
+ ## Setup
17
+
18
+ 1. Create an integration at https://notion.so/my-integrations
19
+ 2. Copy the API key (starts with `ntn_` or `secret_`)
20
+ 3. Store it:
21
+
22
+ ```bash
23
+ mkdir -p ~/.config/notion
24
+ echo "ntn_your_key_here" > ~/.config/notion/api_key
25
+ ```
26
+
27
+ 4. Share target pages/databases with your integration (click "..." → "Connect to" → your integration name)
28
+
29
+ ## API Basics
30
+
31
+ All requests need:
32
+
33
+ ```bash
34
+ NOTION_KEY=$(cat ~/.config/notion/api_key)
35
+ curl -X GET "https://api.notion.com/v1/..." \
36
+ -H "Authorization: Bearer $NOTION_KEY" \
37
+ -H "Notion-Version: 2025-09-03" \
38
+ -H "Content-Type: application/json"
39
+ ```
40
+
41
+ > **Note:** The `Notion-Version` header is required. This skill uses `2025-09-03` (latest). In this version, databases are called "data sources" in the API.
42
+
43
+ ## Common Operations
44
+
45
+ **Search for pages and data sources:**
46
+
47
+ ```bash
48
+ curl -X POST "https://api.notion.com/v1/search" \
49
+ -H "Authorization: Bearer $NOTION_KEY" \
50
+ -H "Notion-Version: 2025-09-03" \
51
+ -H "Content-Type: application/json" \
52
+ -d '{"query": "page title"}'
53
+ ```
54
+
55
+ **Get page:**
56
+
57
+ ```bash
58
+ curl "https://api.notion.com/v1/pages/{page_id}" \
59
+ -H "Authorization: Bearer $NOTION_KEY" \
60
+ -H "Notion-Version: 2025-09-03"
61
+ ```
62
+
63
+ **Get page content (blocks):**
64
+
65
+ ```bash
66
+ curl "https://api.notion.com/v1/blocks/{page_id}/children" \
67
+ -H "Authorization: Bearer $NOTION_KEY" \
68
+ -H "Notion-Version: 2025-09-03"
69
+ ```
70
+
71
+ **Create page in a data source:**
72
+
73
+ ```bash
74
+ curl -X POST "https://api.notion.com/v1/pages" \
75
+ -H "Authorization: Bearer $NOTION_KEY" \
76
+ -H "Notion-Version: 2025-09-03" \
77
+ -H "Content-Type: application/json" \
78
+ -d '{
79
+ "parent": {"database_id": "xxx"},
80
+ "properties": {
81
+ "Name": {"title": [{"text": {"content": "New Item"}}]},
82
+ "Status": {"select": {"name": "Todo"}}
83
+ }
84
+ }'
85
+ ```
86
+
87
+ **Query a data source (database):**
88
+
89
+ ```bash
90
+ curl -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
91
+ -H "Authorization: Bearer $NOTION_KEY" \
92
+ -H "Notion-Version: 2025-09-03" \
93
+ -H "Content-Type: application/json" \
94
+ -d '{
95
+ "filter": {"property": "Status", "select": {"equals": "Active"}},
96
+ "sorts": [{"property": "Date", "direction": "descending"}]
97
+ }'
98
+ ```
99
+
100
+ **Create a data source (database):**
101
+
102
+ ```bash
103
+ curl -X POST "https://api.notion.com/v1/data_sources" \
104
+ -H "Authorization: Bearer $NOTION_KEY" \
105
+ -H "Notion-Version: 2025-09-03" \
106
+ -H "Content-Type: application/json" \
107
+ -d '{
108
+ "parent": {"page_id": "xxx"},
109
+ "title": [{"text": {"content": "My Database"}}],
110
+ "properties": {
111
+ "Name": {"title": {}},
112
+ "Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
113
+ "Date": {"date": {}}
114
+ }
115
+ }'
116
+ ```
117
+
118
+ **Update page properties:**
119
+
120
+ ```bash
121
+ curl -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
122
+ -H "Authorization: Bearer $NOTION_KEY" \
123
+ -H "Notion-Version: 2025-09-03" \
124
+ -H "Content-Type: application/json" \
125
+ -d '{"properties": {"Status": {"select": {"name": "Done"}}}}'
126
+ ```
127
+
128
+ **Add blocks to page:**
129
+
130
+ ```bash
131
+ curl -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
132
+ -H "Authorization: Bearer $NOTION_KEY" \
133
+ -H "Notion-Version: 2025-09-03" \
134
+ -H "Content-Type: application/json" \
135
+ -d '{
136
+ "children": [
137
+ {"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello"}}]}}
138
+ ]
139
+ }'
140
+ ```
141
+
142
+ ## Property Types
143
+
144
+ Common property formats for database items:
145
+
146
+ - **Title:** `{"title": [{"text": {"content": "..."}}]}`
147
+ - **Rich text:** `{"rich_text": [{"text": {"content": "..."}}]}`
148
+ - **Select:** `{"select": {"name": "Option"}}`
149
+ - **Multi-select:** `{"multi_select": [{"name": "A"}, {"name": "B"}]}`
150
+ - **Date:** `{"date": {"start": "2024-01-15", "end": "2024-01-16"}}`
151
+ - **Checkbox:** `{"checkbox": true}`
152
+ - **Number:** `{"number": 42}`
153
+ - **URL:** `{"url": "https://..."}`
154
+ - **Email:** `{"email": "a@b.com"}`
155
+ - **Relation:** `{"relation": [{"id": "page_id"}]}`
156
+
157
+ ## Key Differences in 2025-09-03
158
+
159
+ - **Databases → Data Sources:** Use `/data_sources/` endpoints for queries and retrieval
160
+ - **Two IDs:** Each database now has both a `database_id` and a `data_source_id`
161
+ - Use `database_id` when creating pages (`parent: {"database_id": "..."}`)
162
+ - Use `data_source_id` when querying (`POST /v1/data_sources/{id}/query`)
163
+ - **Search results:** Databases return as `"object": "data_source"` with their `data_source_id`
164
+ - **Parent in responses:** Pages show `parent.data_source_id` alongside `parent.database_id`
165
+ - **Finding the data_source_id:** Search for the database, or call `GET /v1/data_sources/{data_source_id}`
166
+
167
+ ## Notes
168
+
169
+ - Page/database IDs are UUIDs (with or without dashes)
170
+ - The API cannot set database view filters — that's UI-only
171
+ - Rate limit: ~3 requests/second average
172
+ - Use `is_inline: true` when creating data sources to embed them in pages
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: obsidian
3
+ description: Work with Obsidian vaults (plain Markdown notes) and automate via obsidian-cli.
4
+ homepage: https://help.obsidian.md
5
+ metadata:
6
+ {
7
+ "kobold":
8
+ {
9
+ "emoji": "💎",
10
+ "requires": { "bins": ["obsidian-cli"] },
11
+ "install":
12
+ [
13
+ {
14
+ "id": "brew",
15
+ "kind": "brew",
16
+ "formula": "yakitrak/yakitrak/obsidian-cli",
17
+ "bins": ["obsidian-cli"],
18
+ "label": "Install obsidian-cli (brew)",
19
+ },
20
+ ],
21
+ },
22
+ }
23
+ ---
24
+
25
+ # Obsidian
26
+
27
+ Obsidian vault = a normal folder on disk.
28
+
29
+ Vault structure (typical)
30
+
31
+ - Notes: `*.md` (plain text Markdown; edit with any editor)
32
+ - Config: `.obsidian/` (workspace + plugin settings; usually don’t touch from scripts)
33
+ - Canvases: `*.canvas` (JSON)
34
+ - Attachments: whatever folder you chose in Obsidian settings (images/PDFs/etc.)
35
+
36
+ ## Find the active vault(s)
37
+
38
+ Obsidian desktop tracks vaults here (source of truth):
39
+
40
+ - `~/Library/Application Support/obsidian/obsidian.json`
41
+
42
+ `obsidian-cli` resolves vaults from that file; vault name is typically the **folder name** (path suffix).
43
+
44
+ Fast “what vault is active / where are the notes?”
45
+
46
+ - If you’ve already set a default: `obsidian-cli print-default --path-only`
47
+ - Otherwise, read `~/Library/Application Support/obsidian/obsidian.json` and use the vault entry with `"open": true`.
48
+
49
+ Notes
50
+
51
+ - Multiple vaults common (iCloud vs `~/Documents`, work/personal, etc.). Don’t guess; read config.
52
+ - Avoid writing hardcoded vault paths into scripts; prefer reading the config or using `print-default`.
53
+
54
+ ## obsidian-cli quick start
55
+
56
+ Pick a default vault (once):
57
+
58
+ - `obsidian-cli set-default "<vault-folder-name>"`
59
+ - `obsidian-cli print-default` / `obsidian-cli print-default --path-only`
60
+
61
+ Search
62
+
63
+ - `obsidian-cli search "query"` (note names)
64
+ - `obsidian-cli search-content "query"` (inside notes; shows snippets + lines)
65
+
66
+ Create
67
+
68
+ - `obsidian-cli create "Folder/New note" --content "..." --open`
69
+ - Requires Obsidian URI handler (`obsidian://…`) working (Obsidian installed).
70
+ - Avoid creating notes under “hidden” dot-folders (e.g. `.something/...`) via URI; Obsidian may refuse.
71
+
72
+ Move/rename (safe refactor)
73
+
74
+ - `obsidian-cli move "old/path/note" "new/path/note"`
75
+ - Updates `[[wikilinks]]` and common Markdown links across the vault (this is the main win vs `mv`).
76
+
77
+ Delete
78
+
79
+ - `obsidian-cli delete "path/note"`
80
+
81
+ Prefer direct edits when appropriate: open the `.md` file and change it; Obsidian will pick it up.
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: openai-image-gen
3
+ description: Batch-generate images via OpenAI Images API. Random prompt sampler + `index.html` gallery.
4
+ homepage: https://platform.openai.com/docs/api-reference/images
5
+ metadata:
6
+ {
7
+ "kobold":
8
+ {
9
+ "emoji": "🖼️",
10
+ "requires": { "bins": ["python3"], "env": ["OPENAI_API_KEY"] },
11
+ "primaryEnv": "OPENAI_API_KEY",
12
+ "install":
13
+ [
14
+ {
15
+ "id": "python-brew",
16
+ "kind": "brew",
17
+ "formula": "python",
18
+ "bins": ["python3"],
19
+ "label": "Install Python (brew)",
20
+ },
21
+ ],
22
+ },
23
+ }
24
+ ---
25
+
26
+ # OpenAI Image Gen
27
+
28
+ Generate a handful of “random but structured” prompts and render them via the OpenAI Images API.
29
+
30
+ ## Run
31
+
32
+ ```bash
33
+ python3 {baseDir}/scripts/gen.py
34
+ open ~/Projects/tmp/openai-image-gen-*/index.html # if ~/Projects/tmp exists; else ./tmp/...
35
+ ```
36
+
37
+ Useful flags:
38
+
39
+ ```bash
40
+ # GPT image models with various options
41
+ python3 {baseDir}/scripts/gen.py --count 16 --model gpt-image-1
42
+ python3 {baseDir}/scripts/gen.py --prompt "ultra-detailed studio photo of a lobster astronaut" --count 4
43
+ python3 {baseDir}/scripts/gen.py --size 1536x1024 --quality high --out-dir ./out/images
44
+ python3 {baseDir}/scripts/gen.py --model gpt-image-1.5 --background transparent --output-format webp
45
+
46
+ # DALL-E 3 (note: count is automatically limited to 1)
47
+ python3 {baseDir}/scripts/gen.py --model dall-e-3 --quality hd --size 1792x1024 --style vivid
48
+ python3 {baseDir}/scripts/gen.py --model dall-e-3 --style natural --prompt "serene mountain landscape"
49
+
50
+ # DALL-E 2
51
+ python3 {baseDir}/scripts/gen.py --model dall-e-2 --size 512x512 --count 4
52
+ ```
53
+
54
+ ## Model-Specific Parameters
55
+
56
+ Different models support different parameter values. The script automatically selects appropriate defaults based on the model.
57
+
58
+ ### Size
59
+
60
+ - **GPT image models** (`gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`): `1024x1024`, `1536x1024` (landscape), `1024x1536` (portrait), or `auto`
61
+ - Default: `1024x1024`
62
+ - **dall-e-3**: `1024x1024`, `1792x1024`, or `1024x1792`
63
+ - Default: `1024x1024`
64
+ - **dall-e-2**: `256x256`, `512x512`, or `1024x1024`
65
+ - Default: `1024x1024`
66
+
67
+ ### Quality
68
+
69
+ - **GPT image models**: `auto`, `high`, `medium`, or `low`
70
+ - Default: `high`
71
+ - **dall-e-3**: `hd` or `standard`
72
+ - Default: `standard`
73
+ - **dall-e-2**: `standard` only
74
+ - Default: `standard`
75
+
76
+ ### Other Notable Differences
77
+
78
+ - **dall-e-3** only supports generating 1 image at a time (`n=1`). The script automatically limits count to 1 when using this model.
79
+ - **GPT image models** support additional parameters:
80
+ - `--background`: `transparent`, `opaque`, or `auto` (default)
81
+ - `--output-format`: `png` (default), `jpeg`, or `webp`
82
+ - Note: `stream` and `moderation` are available via API but not yet implemented in this script
83
+ - **dall-e-3** has a `--style` parameter: `vivid` (hyper-real, dramatic) or `natural` (more natural looking)
84
+
85
+ ## Output
86
+
87
+ - `*.png`, `*.jpeg`, or `*.webp` images (output format depends on model + `--output-format`)
88
+ - `prompts.json` (prompt → file mapping)
89
+ - `index.html` (thumbnail gallery)