@jairodri/huckleberry-cli 1.0.1 → 1.1.0

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 (745) hide show
  1. package/README.md +85 -0
  2. package/agents/cos.json +2 -5
  3. package/agents/hermes/AGENTS.md +25 -49
  4. package/agents/hermes/fix-kimaki/SKILL.md +19 -92
  5. package/agents/hermes/hermes-fixer.md +44 -74
  6. package/agents/hermes.json +6 -18
  7. package/kanban/SKILL.md +18 -18
  8. package/kanban/package.json +1 -1
  9. package/kanban/src/dispatcher.mjs +1 -1
  10. package/kanban/templates/blog-social-campaign.yaml +6 -2
  11. package/kanban/templates/social-campaign.yaml +9 -4
  12. package/mcp/jev-calibration.mjs +335 -0
  13. package/mcp/jev-client.mjs +119 -0
  14. package/mcp/jev-thresholds.json +27 -0
  15. package/package.json +13 -9
  16. package/scripts/doctor-watchdog.sh +73 -0
  17. package/scripts/install-services.sh +34 -27
  18. package/scripts/self-improve-weekly.sh +34 -0
  19. package/scripts/sync-skills.mjs +121 -0
  20. package/skills/ab-test-setup/SKILL.md +266 -0
  21. package/skills/ab-test-setup/evals/evals.json +105 -0
  22. package/skills/ab-test-setup/references/sample-size-guide.md +263 -0
  23. package/skills/ab-test-setup/references/test-templates.md +277 -0
  24. package/skills/agent-reach/SKILL.md +132 -0
  25. package/skills/agent-reach/references/career.md +29 -0
  26. package/skills/agent-reach/references/dev.md +62 -0
  27. package/skills/agent-reach/references/search.md +33 -0
  28. package/skills/agent-reach/references/social.md +232 -0
  29. package/skills/agent-reach/references/video.md +130 -0
  30. package/skills/agent-reach/references/web.md +50 -0
  31. package/skills/ai-agent-seo/SKILL.md +450 -0
  32. package/skills/ai-cold-email-intelligence/SKILL.md +54 -0
  33. package/skills/ai-cold-email-intelligence/references/prompts.md +21 -0
  34. package/skills/ai-consensus-builder/SKILL.md +324 -0
  35. package/skills/ai-seo/SKILL.md +399 -0
  36. package/skills/ai-seo/evals/evals.json +90 -0
  37. package/skills/ai-seo/references/content-patterns.md +284 -0
  38. package/skills/ai-seo/references/platform-ranking-factors.md +152 -0
  39. package/skills/ai-visibility-audit/SKILL.md +322 -0
  40. package/skills/analytics-tracking/SKILL.md +309 -0
  41. package/skills/analytics-tracking/evals/evals.json +90 -0
  42. package/skills/analytics-tracking/references/event-library.md +260 -0
  43. package/skills/analytics-tracking/references/ga4-implementation.md +300 -0
  44. package/skills/analytics-tracking/references/gtm-implementation.md +390 -0
  45. package/skills/article-generator/SKILL.md +216 -0
  46. package/skills/auto-indexing/SKILL.md +179 -0
  47. package/skills/auto-indexing/scripts/auto-indexing.js +257 -0
  48. package/skills/auto-skill/SKILL.md +151 -0
  49. package/skills/auto-skill/correction-queue.js +102 -0
  50. package/skills/auto-skill/dedup.js +97 -0
  51. package/skills/auto-skill/skill-router.js +224 -0
  52. package/skills/autoresearch/SKILL.md +334 -0
  53. package/skills/autoresearch/autoresearch-autoresearch/SKILL.md.baseline +329 -0
  54. package/skills/autoresearch/autoresearch-autoresearch/changelog.md +34 -0
  55. package/skills/autoresearch/autoresearch-autoresearch/dashboard.html +116 -0
  56. package/skills/autoresearch/autoresearch-autoresearch/evals.md +39 -0
  57. package/skills/autoresearch/autoresearch-autoresearch/results.json +44 -0
  58. package/skills/autoresearch/autoresearch-autoresearch/results.tsv +3 -0
  59. package/skills/autoresearch/eval-guide.md +121 -0
  60. package/skills/b2b-cold-outreach/SKILL.md +322 -0
  61. package/skills/birdclaw/SKILL.md +82 -0
  62. package/skills/brainstorm/SKILL.md +168 -0
  63. package/skills/brand-kit-playground/SKILL.md +312 -0
  64. package/skills/brand-kit-playground/references/html-architecture.md +316 -0
  65. package/skills/brand-kit-playground/references/steal-patterns.md +88 -0
  66. package/skills/brand-voice/SKILL.md +223 -0
  67. package/skills/brand-voice/references/honesty-as-positioning.md +60 -0
  68. package/skills/brand-voice/references/voice-modes.md +1158 -0
  69. package/skills/business-advisory-council/README.md +136 -0
  70. package/skills/business-advisory-council/SKILL.md +94 -0
  71. package/skills/business-advisory-council/business-advisory-council.py +492 -0
  72. package/skills/business-advisory-council/discord-components-decision.json +8 -0
  73. package/skills/business-advisory-council/examples/steve-conley-partnership.json +6 -0
  74. package/skills/business-advisory-council/steve-conley-call-brief.json +6 -0
  75. package/skills/churn-prevention/SKILL.md +305 -0
  76. package/skills/churn-prevention/evals/evals.json +93 -0
  77. package/skills/churn-prevention/references/cancel-flow-patterns.md +316 -0
  78. package/skills/churn-prevention/references/dunning-playbook.md +408 -0
  79. package/skills/claw-compactor/LICENSE +21 -0
  80. package/skills/claw-compactor/README.md +459 -0
  81. package/skills/claw-compactor/SKILL.md +329 -0
  82. package/skills/claw-compactor/benchmark/RESULTS.md +104 -0
  83. package/skills/claw-compactor/benchmark/__init__.py +1 -0
  84. package/skills/claw-compactor/benchmark/compressors.py +520 -0
  85. package/skills/claw-compactor/benchmark/data/sample_01_devops.json +82 -0
  86. package/skills/claw-compactor/benchmark/data/sample_02_trading.json +54 -0
  87. package/skills/claw-compactor/benchmark/data/sample_03_ml_short.json +38 -0
  88. package/skills/claw-compactor/benchmark/data/sample_04_mixed_long.json +318 -0
  89. package/skills/claw-compactor/benchmark/data/sample_05_sysadmin.json +56 -0
  90. package/skills/claw-compactor/benchmark/evaluate.py +278 -0
  91. package/skills/claw-compactor/benchmark/report.py +241 -0
  92. package/skills/claw-compactor/benchmark/results/benchmark_results.json +405 -0
  93. package/skills/claw-compactor/benchmark/run_benchmark.py +238 -0
  94. package/skills/claw-compactor/engram.yaml +49 -0
  95. package/skills/claw-compactor/proxy/README.md +87 -0
  96. package/skills/claw-compactor/proxy/dashboard.html +804 -0
  97. package/skills/claw-compactor/proxy/event-log.mjs +213 -0
  98. package/skills/claw-compactor/proxy/fair-queue.mjs +288 -0
  99. package/skills/claw-compactor/proxy/metrics-store.mjs +425 -0
  100. package/skills/claw-compactor/proxy/package-lock.json +125 -0
  101. package/skills/claw-compactor/proxy/package.json +15 -0
  102. package/skills/claw-compactor/proxy/portal.html +360 -0
  103. package/skills/claw-compactor/proxy/process-registry.mjs +447 -0
  104. package/skills/claw-compactor/proxy/rate-limiter.mjs +117 -0
  105. package/skills/claw-compactor/proxy/redis-client.mjs +75 -0
  106. package/skills/claw-compactor/proxy/retry.mjs +182 -0
  107. package/skills/claw-compactor/proxy/server.mjs +2100 -0
  108. package/skills/claw-compactor/proxy/session-affinity.mjs +177 -0
  109. package/skills/claw-compactor/proxy/start.sh +23 -0
  110. package/skills/claw-compactor/proxy/test/event-log.test.mjs +237 -0
  111. package/skills/claw-compactor/proxy/test/helpers.mjs +103 -0
  112. package/skills/claw-compactor/proxy/test/integration.test.mjs +297 -0
  113. package/skills/claw-compactor/proxy/test/metrics-store.test.mjs +243 -0
  114. package/skills/claw-compactor/proxy/test/process-registry.test.mjs +390 -0
  115. package/skills/claw-compactor/proxy/test/rate-limiter.test.mjs +121 -0
  116. package/skills/claw-compactor/proxy/test/redis-client.test.mjs +62 -0
  117. package/skills/claw-compactor/proxy/test/token-tracker.test.mjs +200 -0
  118. package/skills/claw-compactor/proxy/token-tracker.mjs +482 -0
  119. package/skills/claw-compactor/pyproject.toml +26 -0
  120. package/skills/claw-compactor/references/README.md +44 -0
  121. package/skills/claw-compactor/references/architecture.md +197 -0
  122. package/skills/claw-compactor/references/benchmarks.md +94 -0
  123. package/skills/claw-compactor/references/compression-prompts.md +39 -0
  124. package/skills/claw-compactor/references/compression-techniques.md +219 -0
  125. package/skills/claw-compactor/references/testing.md +160 -0
  126. package/skills/claw-compactor/scripts/audit_memory.py +216 -0
  127. package/skills/claw-compactor/scripts/compress_memory.py +236 -0
  128. package/skills/claw-compactor/scripts/compressed_context.py +280 -0
  129. package/skills/claw-compactor/scripts/dedup_memory.py +147 -0
  130. package/skills/claw-compactor/scripts/dictionary_compress.py +170 -0
  131. package/skills/claw-compactor/scripts/engram-auto.sh +152 -0
  132. package/skills/claw-compactor/scripts/engram_auto.py +695 -0
  133. package/skills/claw-compactor/scripts/engram_cli.py +474 -0
  134. package/skills/claw-compactor/scripts/estimate_tokens.py +131 -0
  135. package/skills/claw-compactor/scripts/generate_summary_tiers.py +292 -0
  136. package/skills/claw-compactor/scripts/lib/__init__.py +34 -0
  137. package/skills/claw-compactor/scripts/lib/config.py +289 -0
  138. package/skills/claw-compactor/scripts/lib/dedup.py +119 -0
  139. package/skills/claw-compactor/scripts/lib/dictionary.py +281 -0
  140. package/skills/claw-compactor/scripts/lib/engram.py +793 -0
  141. package/skills/claw-compactor/scripts/lib/engram_prompts.py +175 -0
  142. package/skills/claw-compactor/scripts/lib/engram_storage.py +254 -0
  143. package/skills/claw-compactor/scripts/lib/exceptions.py +24 -0
  144. package/skills/claw-compactor/scripts/lib/markdown.py +312 -0
  145. package/skills/claw-compactor/scripts/lib/rle.py +165 -0
  146. package/skills/claw-compactor/scripts/lib/tokenizer_optimizer.py +188 -0
  147. package/skills/claw-compactor/scripts/lib/tokens.py +68 -0
  148. package/skills/claw-compactor/scripts/mem_compress.py +788 -0
  149. package/skills/claw-compactor/scripts/observation_compressor.py +346 -0
  150. package/skills/claw-compactor/tests/__init__.py +0 -0
  151. package/skills/claw-compactor/tests/conftest.py +94 -0
  152. package/skills/claw-compactor/tests/test_audit_comprehensive.py +123 -0
  153. package/skills/claw-compactor/tests/test_audit_memory.py +67 -0
  154. package/skills/claw-compactor/tests/test_benchmark.py +122 -0
  155. package/skills/claw-compactor/tests/test_cli_commands.py +228 -0
  156. package/skills/claw-compactor/tests/test_compress_memory.py +109 -0
  157. package/skills/claw-compactor/tests/test_compress_memory_comprehensive.py +191 -0
  158. package/skills/claw-compactor/tests/test_compressed_context.py +145 -0
  159. package/skills/claw-compactor/tests/test_config.py +54 -0
  160. package/skills/claw-compactor/tests/test_dedup_memory.py +124 -0
  161. package/skills/claw-compactor/tests/test_dictionary.py +327 -0
  162. package/skills/claw-compactor/tests/test_dictionary_comprehensive.py +241 -0
  163. package/skills/claw-compactor/tests/test_engram.py +1091 -0
  164. package/skills/claw-compactor/tests/test_engram_auto.py +529 -0
  165. package/skills/claw-compactor/tests/test_error_handling.py +194 -0
  166. package/skills/claw-compactor/tests/test_estimate_tokens.py +99 -0
  167. package/skills/claw-compactor/tests/test_generate_summary_tiers.py +105 -0
  168. package/skills/claw-compactor/tests/test_integration.py +249 -0
  169. package/skills/claw-compactor/tests/test_lib_dedup.py +135 -0
  170. package/skills/claw-compactor/tests/test_lib_markdown.py +388 -0
  171. package/skills/claw-compactor/tests/test_lib_tokens.py +82 -0
  172. package/skills/claw-compactor/tests/test_main_entry.py +176 -0
  173. package/skills/claw-compactor/tests/test_markdown_advanced.py +284 -0
  174. package/skills/claw-compactor/tests/test_new_features.py +77 -0
  175. package/skills/claw-compactor/tests/test_observation_comprehensive.py +261 -0
  176. package/skills/claw-compactor/tests/test_observation_compressor.py +128 -0
  177. package/skills/claw-compactor/tests/test_performance.py +172 -0
  178. package/skills/claw-compactor/tests/test_pipeline.py +109 -0
  179. package/skills/claw-compactor/tests/test_real_workspace.py +161 -0
  180. package/skills/claw-compactor/tests/test_rle.py +114 -0
  181. package/skills/claw-compactor/tests/test_rle_comprehensive.py +151 -0
  182. package/skills/claw-compactor/tests/test_roundtrip.py +253 -0
  183. package/skills/claw-compactor/tests/test_roundtrip_comprehensive.py +192 -0
  184. package/skills/claw-compactor/tests/test_tiers_comprehensive.py +171 -0
  185. package/skills/claw-compactor/tests/test_token_economics.py +237 -0
  186. package/skills/claw-compactor/tests/test_tokenizer_optimizer.py +175 -0
  187. package/skills/claw-compactor/tests/test_tokenizer_optimizer_comprehensive.py +241 -0
  188. package/skills/claw-compactor/tests/test_tokens.py +27 -0
  189. package/skills/cmo/CHANGELOG.md +61 -0
  190. package/skills/cmo/SKILL.md +500 -0
  191. package/skills/cmo/references/ai-slop-patterns.md +56 -0
  192. package/skills/cmo/references/analytics-guide.md +152 -0
  193. package/skills/cmo/references/ideas-library.md +197 -0
  194. package/skills/cmo/rules/brand-file-map.md +198 -0
  195. package/skills/cmo/rules/brand-memory.md +158 -0
  196. package/skills/cmo/rules/cli-runtime-index.md +95 -0
  197. package/skills/cmo/rules/command-reference.md +167 -0
  198. package/skills/cmo/rules/communication.md +15 -0
  199. package/skills/cmo/rules/context-switch.md +101 -0
  200. package/skills/cmo/rules/ecosystem.md +125 -0
  201. package/skills/cmo/rules/error-recovery.md +98 -0
  202. package/skills/cmo/rules/learning-loop.md +170 -0
  203. package/skills/cmo/rules/monorepo.md +78 -0
  204. package/skills/cmo/rules/output-format.md +124 -0
  205. package/skills/cmo/rules/persona.md +15 -0
  206. package/skills/cmo/rules/playbooks.md +327 -0
  207. package/skills/cmo/rules/progressive-enhancement.md +231 -0
  208. package/skills/cmo/rules/publish-index.md +106 -0
  209. package/skills/cmo/rules/quality-gate.md +90 -0
  210. package/skills/cmo/rules/recency-grounding.md +124 -0
  211. package/skills/cmo/rules/safety.md +80 -0
  212. package/skills/cmo/rules/studio-api-index.md +138 -0
  213. package/skills/cmo/rules/studio-integration.md +147 -0
  214. package/skills/cmo/rules/sub-agents.md +167 -0
  215. package/skills/cold-email/SKILL.md +240 -0
  216. package/skills/cold-email/evals/evals.json +94 -0
  217. package/skills/cold-email/references/benchmarks.md +83 -0
  218. package/skills/cold-email/references/follow-up-sequences.md +81 -0
  219. package/skills/cold-email/references/frameworks.md +90 -0
  220. package/skills/cold-email/references/personalization.md +79 -0
  221. package/skills/cold-email/references/subject-lines.md +53 -0
  222. package/skills/competitive-intel/SKILL.md +433 -0
  223. package/skills/competitive-intel/references/competitive-frameworks.md +145 -0
  224. package/skills/competitor-alternatives/SKILL.md +362 -0
  225. package/skills/competitor-alternatives/evals/evals.json +93 -0
  226. package/skills/competitor-alternatives/references/content-architecture.md +271 -0
  227. package/skills/competitor-alternatives/references/templates.md +223 -0
  228. package/skills/concreteness-fixer/SKILL.md +483 -0
  229. package/skills/concreteness-fixer/scripts/validation/concreteness-validator.js +221 -0
  230. package/skills/concreteness-fixer/utils/execFileNoThrow.js +16 -0
  231. package/skills/content-atomizer/SKILL.md +424 -0
  232. package/skills/content-atomizer/references/hook-strategies.md +56 -0
  233. package/skills/content-atomizer/references/platform-specs.md +118 -0
  234. package/skills/content-atomizer/references/platforms/bluesky.md +64 -0
  235. package/skills/content-atomizer/references/platforms/instagram.md +77 -0
  236. package/skills/content-atomizer/references/platforms/linkedin.md +120 -0
  237. package/skills/content-atomizer/references/platforms/reddit.md +73 -0
  238. package/skills/content-atomizer/references/platforms/threads.md +64 -0
  239. package/skills/content-atomizer/references/platforms/tiktok.md +55 -0
  240. package/skills/content-atomizer/references/platforms/twitter.md +123 -0
  241. package/skills/content-atomizer/references/platforms/youtube.md +56 -0
  242. package/skills/content-atomizer/references/tweet-patterns.md +40 -0
  243. package/skills/content-repost-manager/SKILL.md +245 -0
  244. package/skills/content-repost-manager/scripts/content-repost-scan.py +133 -0
  245. package/skills/context-recovery/.clawdhub/origin.json +7 -0
  246. package/skills/context-recovery/SKILL.md +198 -0
  247. package/skills/context-recovery/_meta.json +6 -0
  248. package/skills/conversion-flow-cro/SKILL.md +248 -0
  249. package/skills/conversion-flow-cro/references/flow-benchmarks.md +158 -0
  250. package/skills/copy-editing/SKILL.md +474 -0
  251. package/skills/copy-editing/evals/evals.json +89 -0
  252. package/skills/copy-editing/references/plain-english-alternatives.md +394 -0
  253. package/skills/copywriting/SKILL.md +349 -0
  254. package/skills/copywriting/evals/evals.json +111 -0
  255. package/skills/copywriting/references/awareness-level-guide.md +227 -0
  256. package/skills/copywriting/references/copy-frameworks.md +389 -0
  257. package/skills/copywriting/references/natural-transitions.md +272 -0
  258. package/skills/creative/SKILL.md +365 -0
  259. package/skills/creative/modes/ad-creative.md +1748 -0
  260. package/skills/creative/modes/product-photo.md +1520 -0
  261. package/skills/creative/modes/product-video.md +1657 -0
  262. package/skills/creative/modes/social-graphics.md +1511 -0
  263. package/skills/creative/modes/talking-head.md +2208 -0
  264. package/skills/creative/references/VISUAL_INTELLIGENCE.md +1233 -0
  265. package/skills/deep-serp-article/SKILL.md +677 -0
  266. package/skills/deep-serp-article/SKILL.md.bak +530 -0
  267. package/skills/earned-media/SKILL.md +260 -0
  268. package/skills/email-sequences/SKILL.md +446 -0
  269. package/skills/email-sequences/references/sequence-templates.md +1217 -0
  270. package/skills/firecrawl/.skill-meta.json +13 -0
  271. package/skills/firecrawl/SKILL.md +154 -0
  272. package/skills/firecrawl/rules/install.md +63 -0
  273. package/skills/firecrawl/rules/security.md +26 -0
  274. package/skills/form-cro/SKILL.md +429 -0
  275. package/skills/form-cro/evals/evals.json +90 -0
  276. package/skills/free-tool-strategy/SKILL.md +325 -0
  277. package/skills/free-tool-strategy/evals/evals.json +90 -0
  278. package/skills/free-tool-strategy/references/tool-types.md +253 -0
  279. package/skills/frontend-slides/SKILL.md +248 -0
  280. package/skills/frontend-slides/STYLE_PRESETS.md +347 -0
  281. package/skills/frontend-slides/animation-patterns.md +110 -0
  282. package/skills/frontend-slides/html-template.md +347 -0
  283. package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
  284. package/skills/frontend-slides/viewport-base.css +153 -0
  285. package/skills/guardrail-framework/SKILL.md +319 -0
  286. package/skills/hook-generator/SKILL.md +438 -0
  287. package/skills/hook-generator/database/2026-PLATFORM-RESEARCH.md +211 -0
  288. package/skills/hook-generator/database/instagram-hooks.json +591 -0
  289. package/skills/hook-generator/database/linkedin-hooks.json +502 -0
  290. package/skills/hook-generator/database/medium-hooks.json +181 -0
  291. package/skills/hook-generator/database/tiktok-hooks.json +337 -0
  292. package/skills/hook-generator/database/twitter-hooks.json +567 -0
  293. package/skills/hook-generator/database/youtube-hooks.json +275 -0
  294. package/skills/hook-generator/package-lock.json +24 -0
  295. package/skills/hook-generator/package.json +5 -0
  296. package/skills/hook-generator/references/hook-generation-system.md +257 -0
  297. package/skills/hook-generator/references/hook-performance-analysis.json +153 -0
  298. package/skills/hook-generator/references/hooks-library.md +128 -0
  299. package/skills/hook-generator/references/platform-hook-frameworks.md +275 -0
  300. package/skills/hook-generator/scripts/generate-hooks-unified.js +722 -0
  301. package/skills/hook-generator/scripts/generate-hooks.js +225 -0
  302. package/skills/hook-generator/scripts/generate.sh +36 -0
  303. package/skills/hook-generator/scripts/ralph-hook-enhancer.js +864 -0
  304. package/skills/hook-generator/scripts/test-gemini-output.js +51 -0
  305. package/skills/humanizer/README.md +120 -0
  306. package/skills/humanizer/SKILL.md +699 -0
  307. package/skills/image-gen/SKILL.md +277 -0
  308. package/skills/image-gen/references/prompt-patterns.md +114 -0
  309. package/skills/image-gen/references/visual-metaphors.md +51 -0
  310. package/skills/impeccable/SKILL.md +86 -0
  311. package/skills/impeccable/reference/adapt.md +312 -0
  312. package/skills/impeccable/reference/adapt.native.md +58 -0
  313. package/skills/impeccable/reference/android.md +40 -0
  314. package/skills/impeccable/reference/animate.md +86 -0
  315. package/skills/impeccable/reference/audit.md +136 -0
  316. package/skills/impeccable/reference/audit.native.md +139 -0
  317. package/skills/impeccable/reference/bolder.md +31 -0
  318. package/skills/impeccable/reference/clarify.md +94 -0
  319. package/skills/impeccable/reference/colorize.md +86 -0
  320. package/skills/impeccable/reference/craft-floor.md +42 -0
  321. package/skills/impeccable/reference/craft.md +5 -0
  322. package/skills/impeccable/reference/critique.md +788 -0
  323. package/skills/impeccable/reference/degraded/asset-producer.md +90 -0
  324. package/skills/impeccable/reference/degraded/documenter.md +24 -0
  325. package/skills/impeccable/reference/degraded/finish-reviewer.md +37 -0
  326. package/skills/impeccable/reference/degraded/manual-edit-applier.md +92 -0
  327. package/skills/impeccable/reference/delight.md +70 -0
  328. package/skills/impeccable/reference/distill.md +111 -0
  329. package/skills/impeccable/reference/doctor.md +53 -0
  330. package/skills/impeccable/reference/document.md +416 -0
  331. package/skills/impeccable/reference/extract.md +69 -0
  332. package/skills/impeccable/reference/harden.md +336 -0
  333. package/skills/impeccable/reference/hooks.md +105 -0
  334. package/skills/impeccable/reference/init.md +125 -0
  335. package/skills/impeccable/reference/ios.md +45 -0
  336. package/skills/impeccable/reference/layout.md +84 -0
  337. package/skills/impeccable/reference/live-setup.md +102 -0
  338. package/skills/impeccable/reference/live.md +323 -0
  339. package/skills/impeccable/reference/new-work.md +110 -0
  340. package/skills/impeccable/reference/onboard.md +234 -0
  341. package/skills/impeccable/reference/operate.md +61 -0
  342. package/skills/impeccable/reference/optimize.md +258 -0
  343. package/skills/impeccable/reference/overdrive.md +127 -0
  344. package/skills/impeccable/reference/polish.md +97 -0
  345. package/skills/impeccable/reference/quieter.md +99 -0
  346. package/skills/impeccable/reference/routing.md +18 -0
  347. package/skills/impeccable/reference/shape.md +59 -0
  348. package/skills/impeccable/reference/typeset.md +80 -0
  349. package/skills/impeccable/reference/visualize.md +49 -0
  350. package/skills/impeccable/scripts/command-metadata.json +94 -0
  351. package/skills/impeccable/scripts/concept-seed.mjs +558 -0
  352. package/skills/impeccable/scripts/context-signals.mjs +334 -0
  353. package/skills/impeccable/scripts/context.mjs +1467 -0
  354. package/skills/impeccable/scripts/critique-storage.mjs +213 -0
  355. package/skills/impeccable/scripts/detect-csp.mjs +198 -0
  356. package/skills/impeccable/scripts/detect.mjs +21 -0
  357. package/skills/impeccable/scripts/detector/browser/injected/index.mjs +2023 -0
  358. package/skills/impeccable/scripts/detector/cli/main.mjs +438 -0
  359. package/skills/impeccable/scripts/detector/design-system.mjs +1046 -0
  360. package/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +8283 -0
  361. package/skills/impeccable/scripts/detector/detect-antipatterns.mjs +50 -0
  362. package/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +372 -0
  363. package/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +1168 -0
  364. package/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +1186 -0
  365. package/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +264 -0
  366. package/skills/impeccable/scripts/detector/engines/visual/screenshot-contrast.mjs +189 -0
  367. package/skills/impeccable/scripts/detector/findings.mjs +18 -0
  368. package/skills/impeccable/scripts/detector/node/file-system.mjs +203 -0
  369. package/skills/impeccable/scripts/detector/profile/profiler.mjs +166 -0
  370. package/skills/impeccable/scripts/detector/registry/antipatterns.mjs +617 -0
  371. package/skills/impeccable/scripts/detector/rules/checks.mjs +5580 -0
  372. package/skills/impeccable/scripts/detector/shared/color.mjs +124 -0
  373. package/skills/impeccable/scripts/detector/shared/constants.mjs +112 -0
  374. package/skills/impeccable/scripts/detector/shared/fonts.mjs +30 -0
  375. package/skills/impeccable/scripts/detector/shared/inline-ignores.mjs +148 -0
  376. package/skills/impeccable/scripts/detector/shared/page.mjs +7 -0
  377. package/skills/impeccable/scripts/doctor.mjs +336 -0
  378. package/skills/impeccable/scripts/embed-prompt.mjs +133 -0
  379. package/skills/impeccable/scripts/generate-image.mjs +240 -0
  380. package/skills/impeccable/scripts/hook-admin.mjs +801 -0
  381. package/skills/impeccable/scripts/hook-before-edit.mjs +508 -0
  382. package/skills/impeccable/scripts/hook-lib.mjs +2153 -0
  383. package/skills/impeccable/scripts/hook.mjs +78 -0
  384. package/skills/impeccable/scripts/lib/artifact-schema.mjs +93 -0
  385. package/skills/impeccable/scripts/lib/composition-catalog.mjs +200 -0
  386. package/skills/impeccable/scripts/lib/concept-catalog.mjs +384 -0
  387. package/skills/impeccable/scripts/lib/design-parser.mjs +925 -0
  388. package/skills/impeccable/scripts/lib/impeccable-config.mjs +658 -0
  389. package/skills/impeccable/scripts/lib/impeccable-paths.mjs +137 -0
  390. package/skills/impeccable/scripts/lib/is-generated.mjs +69 -0
  391. package/skills/impeccable/scripts/lib/provider.mjs +5 -0
  392. package/skills/impeccable/scripts/lib/roll-selection.mjs +362 -0
  393. package/skills/impeccable/scripts/lib/staleness-deep.mjs +478 -0
  394. package/skills/impeccable/scripts/lib/staleness-notice.mjs +169 -0
  395. package/skills/impeccable/scripts/lib/staleness.mjs +457 -0
  396. package/skills/impeccable/scripts/lib/surface-briefs.mjs +151 -0
  397. package/skills/impeccable/scripts/lib/target-args.mjs +42 -0
  398. package/skills/impeccable/scripts/lib/target-slug.mjs +33 -0
  399. package/skills/impeccable/scripts/lib/template-extensions.mjs +146 -0
  400. package/skills/impeccable/scripts/live/accept-css.mjs +617 -0
  401. package/skills/impeccable/scripts/live/accept-verify.mjs +60 -0
  402. package/skills/impeccable/scripts/live/browser-script-parts.mjs +55 -0
  403. package/skills/impeccable/scripts/live/completion.mjs +28 -0
  404. package/skills/impeccable/scripts/live/event-validation.mjs +199 -0
  405. package/skills/impeccable/scripts/live/frameworks/astro.mjs +47 -0
  406. package/skills/impeccable/scripts/live/frameworks/detect-utils.mjs +73 -0
  407. package/skills/impeccable/scripts/live/frameworks/index.mjs +143 -0
  408. package/skills/impeccable/scripts/live/frameworks/journal.mjs +197 -0
  409. package/skills/impeccable/scripts/live/frameworks/nextjs.mjs +49 -0
  410. package/skills/impeccable/scripts/live/frameworks/nuxt.mjs +161 -0
  411. package/skills/impeccable/scripts/live/frameworks/script-src.mjs +17 -0
  412. package/skills/impeccable/scripts/live/frameworks/static-html.mjs +26 -0
  413. package/skills/impeccable/scripts/live/frameworks/sveltekit.mjs +71 -0
  414. package/skills/impeccable/scripts/live/frameworks/tag-strategy.mjs +247 -0
  415. package/skills/impeccable/scripts/live/frameworks/tanstack-start.mjs +70 -0
  416. package/skills/impeccable/scripts/live/frameworks/vite-generic.mjs +42 -0
  417. package/skills/impeccable/scripts/live/generation-preflight.mjs +149 -0
  418. package/skills/impeccable/scripts/live/insert-ui.mjs +458 -0
  419. package/skills/impeccable/scripts/live/instructions.mjs +142 -0
  420. package/skills/impeccable/scripts/live/manual-apply.mjs +939 -0
  421. package/skills/impeccable/scripts/live/manual-edit-routes.mjs +357 -0
  422. package/skills/impeccable/scripts/live/manual-edits-buffer.mjs +152 -0
  423. package/skills/impeccable/scripts/live/poll-lanes.mjs +14 -0
  424. package/skills/impeccable/scripts/live/roots.mjs +508 -0
  425. package/skills/impeccable/scripts/live/session-store.mjs +563 -0
  426. package/skills/impeccable/scripts/live/source-lock.mjs +105 -0
  427. package/skills/impeccable/scripts/live/source-search.mjs +105 -0
  428. package/skills/impeccable/scripts/live/svelte-ast.mjs +961 -0
  429. package/skills/impeccable/scripts/live/svelte-component.mjs +1342 -0
  430. package/skills/impeccable/scripts/live/sveltekit-adapter.mjs +316 -0
  431. package/skills/impeccable/scripts/live/tanstack-adapter.mjs +280 -0
  432. package/skills/impeccable/scripts/live/ui-core.mjs +180 -0
  433. package/skills/impeccable/scripts/live/vocabulary.mjs +171 -0
  434. package/skills/impeccable/scripts/live-accept.mjs +954 -0
  435. package/skills/impeccable/scripts/live-browser-dom.js +146 -0
  436. package/skills/impeccable/scripts/live-browser-session.js +123 -0
  437. package/skills/impeccable/scripts/live-browser.js +12520 -0
  438. package/skills/impeccable/scripts/live-commit-manual-edits.mjs +1244 -0
  439. package/skills/impeccable/scripts/live-complete.mjs +107 -0
  440. package/skills/impeccable/scripts/live-copy-edit-agent.mjs +683 -0
  441. package/skills/impeccable/scripts/live-discard-manual-edits.mjs +51 -0
  442. package/skills/impeccable/scripts/live-inject.mjs +503 -0
  443. package/skills/impeccable/scripts/live-insert.mjs +292 -0
  444. package/skills/impeccable/scripts/live-manual-edit-evidence.mjs +368 -0
  445. package/skills/impeccable/scripts/live-poll.mjs +429 -0
  446. package/skills/impeccable/scripts/live-resume.mjs +123 -0
  447. package/skills/impeccable/scripts/live-server.mjs +1669 -0
  448. package/skills/impeccable/scripts/live-status.mjs +71 -0
  449. package/skills/impeccable/scripts/live-target.mjs +30 -0
  450. package/skills/impeccable/scripts/live-wrap.mjs +927 -0
  451. package/skills/impeccable/scripts/live.mjs +359 -0
  452. package/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
  453. package/skills/impeccable/scripts/palette.mjs +628 -0
  454. package/skills/impeccable/scripts/pin.mjs +221 -0
  455. package/skills/impeccable/scripts/serve-question.mjs +932 -0
  456. package/skills/impeccable/scripts/surface-brief.mjs +74 -0
  457. package/skills/inkstone-admin/SKILL.md +66 -0
  458. package/skills/jev-hook-gate/SKILL.md +111 -0
  459. package/skills/keyword-research/SKILL.md +503 -0
  460. package/skills/keyword-research/references/dr-cap-and-confidence.md +62 -0
  461. package/skills/keyword-research/references/keyword-examples.md +769 -0
  462. package/skills/landing-page-architect/SKILL.md +585 -0
  463. package/skills/landing-page-architect/references/architecture-reference.md +32 -0
  464. package/skills/launch-strategy/SKILL.md +384 -0
  465. package/skills/launch-strategy/evals/evals.json +91 -0
  466. package/skills/launch-strategy/references/launch-checklist.md +209 -0
  467. package/skills/launch-strategy/references/launch-timeline.md +159 -0
  468. package/skills/lead-email-craft/SKILL.md +522 -0
  469. package/skills/lead-magnets/SKILL.md +310 -0
  470. package/skills/lead-magnets/references/benchmarks.md +129 -0
  471. package/skills/lead-magnets/references/format-guide.md +196 -0
  472. package/skills/link-building-seo/SKILL.md +210 -0
  473. package/skills/lint-report.txt +1 -0
  474. package/skills/manifest.json +129 -0
  475. package/skills/marketing-demo/SKILL.md +249 -0
  476. package/skills/marketing-demo/references/remotion-examples.md +281 -0
  477. package/skills/marketing-ideas/SKILL.md +167 -0
  478. package/skills/marketing-ideas/evals/evals.json +90 -0
  479. package/skills/marketing-ideas/references/ideas-by-category.md +366 -0
  480. package/skills/marketing-psychology/SKILL.md +374 -0
  481. package/skills/marketing-psychology/evals/evals.json +88 -0
  482. package/skills/marketing-psychology/references/case-studies.md +148 -0
  483. package/skills/narrative-research-article/SKILL.md +469 -0
  484. package/skills/narrative-research-article/references/lanusse-patterns.md +166 -0
  485. package/skills/notebooklm/SKILL.md +674 -0
  486. package/skills/off-page-seo/SKILL.md +219 -0
  487. package/skills/onboarding-cro/SKILL.md +220 -0
  488. package/skills/onboarding-cro/evals/evals.json +92 -0
  489. package/skills/onboarding-cro/references/experiments.md +258 -0
  490. package/skills/original-research/SKILL.md +388 -0
  491. package/skills/page-cro/SKILL.md +269 -0
  492. package/skills/page-cro/references/cro-benchmarks.md +140 -0
  493. package/skills/paper-marketing/SKILL.md +448 -0
  494. package/skills/paper-marketing/references/agent-quality-rubric.md +68 -0
  495. package/skills/paper-marketing/references/brand-system-template.md +120 -0
  496. package/skills/paper-marketing/references/paper-mcp-rules.md +71 -0
  497. package/skills/paper-marketing/references/platform-conventions.md +43 -0
  498. package/skills/paywall-upgrade-cro/SKILL.md +227 -0
  499. package/skills/paywall-upgrade-cro/evals/evals.json +93 -0
  500. package/skills/paywall-upgrade-cro/references/experiments.md +164 -0
  501. package/skills/platform-formatting/SKILL.md +51 -0
  502. package/skills/popup-cro/SKILL.md +454 -0
  503. package/skills/popup-cro/evals/evals.json +94 -0
  504. package/skills/positioning-angles/SKILL.md +524 -0
  505. package/skills/positioning-angles/references/ad-matrix-and-examples.md +176 -0
  506. package/skills/positioning-angles/references/angle-frameworks.md +187 -0
  507. package/skills/positioning-angles/references/dunford-positioning.md +135 -0
  508. package/skills/positioning-angles/references/hormozi-offer.md +247 -0
  509. package/skills/positioning-angles/references/schwartz-sophistication.md +166 -0
  510. package/skills/positioning-angles/references/unique-mechanism.md +162 -0
  511. package/skills/pricing-strategy/SKILL.md +346 -0
  512. package/skills/pricing-strategy/evals/evals.json +90 -0
  513. package/skills/pricing-strategy/references/research-methods.md +152 -0
  514. package/skills/pricing-strategy/references/tier-structure.md +307 -0
  515. package/skills/programmatic-seo/SKILL.md +238 -0
  516. package/skills/programmatic-seo/evals/evals.json +94 -0
  517. package/skills/programmatic-seo/references/playbooks.md +308 -0
  518. package/skills/project-rag/SKILL.md +127 -0
  519. package/skills/quality-gate/SKILL.md +519 -0
  520. package/skills/quality-gate/judge-personas/buyer.md +47 -0
  521. package/skills/quality-gate/judge-personas/expert.md +47 -0
  522. package/skills/quality-gate/judge-personas/outsider.md +47 -0
  523. package/skills/quality-gate/judge-personas/scanner.md +41 -0
  524. package/skills/quality-gate/judge-personas/skeptic.md +40 -0
  525. package/skills/referral-program/SKILL.md +290 -0
  526. package/skills/referral-program/evals/evals.json +89 -0
  527. package/skills/referral-program/references/affiliate-programs.md +163 -0
  528. package/skills/referral-program/references/program-examples.md +143 -0
  529. package/skills/review-sites/SKILL.md +279 -0
  530. package/skills/revops/SKILL.md +343 -0
  531. package/skills/revops/evals/evals.json +91 -0
  532. package/skills/revops/references/automation-playbooks.md +290 -0
  533. package/skills/revops/references/lifecycle-definitions.md +278 -0
  534. package/skills/revops/references/routing-rules.md +203 -0
  535. package/skills/revops/references/scoring-models.md +247 -0
  536. package/skills/saas-product-seo/SKILL.md +324 -0
  537. package/skills/sales-enablement/SKILL.md +349 -0
  538. package/skills/sales-enablement/evals/evals.json +91 -0
  539. package/skills/sales-enablement/references/deck-frameworks.md +263 -0
  540. package/skills/sales-enablement/references/demo-scripts.md +355 -0
  541. package/skills/sales-enablement/references/objection-library.md +270 -0
  542. package/skills/sales-enablement/references/one-pager-templates.md +208 -0
  543. package/skills/schema-markup/SKILL.md +179 -0
  544. package/skills/schema-markup/evals/evals.json +87 -0
  545. package/skills/schema-markup/references/schema-examples.md +398 -0
  546. package/skills/self-improve/SKILL.md +166 -0
  547. package/skills/self-improving-agent/README.md +243 -0
  548. package/skills/self-improving-agent/SKILL.md +437 -0
  549. package/skills/self-improving-agent/scripts/__init__.py +16 -0
  550. package/skills/self-improving-agent/scripts/__pycache__/auto_detect.cpython-314.pyc +0 -0
  551. package/skills/self-improving-agent/scripts/__pycache__/nlm_curation.cpython-314.pyc +0 -0
  552. package/skills/self-improving-agent/scripts/__pycache__/self_improving_agent.cpython-314.pyc +0 -0
  553. package/skills/self-improving-agent/scripts/auto_detect.py +270 -0
  554. package/skills/self-improving-agent/scripts/init_expertise_registry.py +89 -0
  555. package/skills/self-improving-agent/scripts/nlm_curation.py +259 -0
  556. package/skills/self-improving-agent/scripts/self-improving-agent +113 -0
  557. package/skills/self-improving-agent/scripts/self_improving_agent.py +603 -0
  558. package/skills/self-improving-agent/scripts/test_curation_scorer.py +20 -0
  559. package/skills/self-improving-agent/scripts/test_self_improving.py +184 -0
  560. package/skills/send-email/SKILL.md +426 -0
  561. package/skills/send-email/references/batch-email-examples.md +807 -0
  562. package/skills/send-email/references/best-practices.md +453 -0
  563. package/skills/send-email/references/installation.md +123 -0
  564. package/skills/send-email/references/single-email-examples.md +470 -0
  565. package/skills/send-email/references/webhooks.md +221 -0
  566. package/skills/seo-audit/SKILL.md +362 -0
  567. package/skills/seo-audit/references/ai-writing-detection.md +200 -0
  568. package/skills/seo-audit/references/architecture-patterns.md +271 -0
  569. package/skills/seo-audit/references/schema-templates.md +427 -0
  570. package/skills/seo-content/SKILL.md +510 -0
  571. package/skills/seo-content/references/anti-ai-detection.md +184 -0
  572. package/skills/seo-content/references/content-structures.md +148 -0
  573. package/skills/seo-content/references/eeat-examples.md +235 -0
  574. package/skills/seo-content/references/on-page-seo.md +261 -0
  575. package/skills/seo-content/references/pseo-playbooks.md +226 -0
  576. package/skills/seo-content/references/schema-templates.md +104 -0
  577. package/skills/seo-content/references/serp-analysis-format.md +151 -0
  578. package/skills/seo-machine/SKILL.md +331 -0
  579. package/skills/seo-machine/assets/brand-template.md +73 -0
  580. package/skills/seo-machine/assets/link-inventory-template.md +74 -0
  581. package/skills/seo-machine/assets/roadmap-template.md +184 -0
  582. package/skills/seo-machine/references/api-stack-recipes.md +230 -0
  583. package/skills/seo-machine/references/exa-recipes.md +260 -0
  584. package/skills/seo-machine/references/manual-research.md +73 -0
  585. package/skills/seo-machine/references/methodology.md +87 -0
  586. package/skills/seo-machine/references/off-page.md +123 -0
  587. package/skills/seo-machine/references/patterns/alternatives.md +176 -0
  588. package/skills/seo-machine/references/patterns/compare.md +105 -0
  589. package/skills/seo-machine/references/patterns/playbooks.md +106 -0
  590. package/skills/seo-machine/references/patterns/use-case.md +109 -0
  591. package/skills/seo-machine/references/quality-bars.md +99 -0
  592. package/skills/seo-machine/references/stacks/astro.md +156 -0
  593. package/skills/seo-machine/references/stacks/detection.md +61 -0
  594. package/skills/seo-machine/references/stacks/markdown-fallback.md +181 -0
  595. package/skills/seo-machine/references/stacks/nextjs.md +108 -0
  596. package/skills/seo-machine/references/stacks/rails-inertia.md +99 -0
  597. package/skills/seo-machine/references/striking-distance.md +116 -0
  598. package/skills/seo-machine/references/technical-audit.md +153 -0
  599. package/skills/seo-machine/scripts/link_audit.py +265 -0
  600. package/skills/seo-machine/scripts/tech_audit.py +221 -0
  601. package/skills/seo-machine/scripts/word_count.py +154 -0
  602. package/skills/sharp-thesis-validator/SKILL.md +393 -0
  603. package/skills/sharp-thesis-validator/examples.md +186 -0
  604. package/skills/signup-flow-cro/SKILL.md +359 -0
  605. package/skills/signup-flow-cro/evals/evals.json +88 -0
  606. package/skills/site-architecture/SKILL.md +357 -0
  607. package/skills/site-architecture/evals/evals.json +88 -0
  608. package/skills/site-architecture/references/mermaid-templates.md +216 -0
  609. package/skills/site-architecture/references/navigation-patterns.md +305 -0
  610. package/skills/site-architecture/references/site-type-templates.md +293 -0
  611. package/skills/skill-self-improvement/SKILL.md +151 -0
  612. package/skills/slideshow-script/SKILL.md +274 -0
  613. package/skills/slideshow-script/references/content-spec-schema.md +77 -0
  614. package/skills/slideshow-script/references/frameworks.md +84 -0
  615. package/skills/slideshow-script/references/paips-framework.md +37 -0
  616. package/skills/social-campaign/SKILL.md +419 -0
  617. package/skills/social-campaign/references/paper-mcp-workflow.md +48 -0
  618. package/skills/social-content/SKILL.md +359 -0
  619. package/skills/social-content/evals/evals.json +92 -0
  620. package/skills/social-content/references/platforms.md +170 -0
  621. package/skills/social-content/references/post-templates.md +177 -0
  622. package/skills/social-content/references/reverse-engineering.md +195 -0
  623. package/skills/social-worker/SKILL.md +204 -0
  624. package/skills/startup-launcher/SKILL.md +252 -0
  625. package/skills/startup-launcher/references/file-router.md +64 -0
  626. package/skills/startup-launcher/references/platform-matrix.md +65 -0
  627. package/skills/startup-launcher/references/platforms/alternativeto.md +283 -0
  628. package/skills/startup-launcher/references/platforms/appsumo.md +495 -0
  629. package/skills/startup-launcher/references/platforms/auraplusplus.md +736 -0
  630. package/skills/startup-launcher/references/platforms/betalist.md +98 -0
  631. package/skills/startup-launcher/references/platforms/capterra.md +276 -0
  632. package/skills/startup-launcher/references/platforms/crunchbase.md +514 -0
  633. package/skills/startup-launcher/references/platforms/dealify.md +291 -0
  634. package/skills/startup-launcher/references/platforms/dealmirror.md +313 -0
  635. package/skills/startup-launcher/references/platforms/desifounder.md +490 -0
  636. package/skills/startup-launcher/references/platforms/devhunt.md +210 -0
  637. package/skills/startup-launcher/references/platforms/devpost.md +448 -0
  638. package/skills/startup-launcher/references/platforms/fazier.md +56 -0
  639. package/skills/startup-launcher/references/platforms/firsto.md +489 -0
  640. package/skills/startup-launcher/references/platforms/g2.md +226 -0
  641. package/skills/startup-launcher/references/platforms/hackernews.md +99 -0
  642. package/skills/startup-launcher/references/platforms/hackernoon.md +385 -0
  643. package/skills/startup-launcher/references/platforms/indiedeals.md +367 -0
  644. package/skills/startup-launcher/references/platforms/indiehackers.md +80 -0
  645. package/skills/startup-launcher/references/platforms/kenmoo.md +231 -0
  646. package/skills/startup-launcher/references/platforms/labstartups.md +618 -0
  647. package/skills/startup-launcher/references/platforms/launchboard.md +307 -0
  648. package/skills/startup-launcher/references/platforms/launchfast.md +560 -0
  649. package/skills/startup-launcher/references/platforms/launchigniter.md +56 -0
  650. package/skills/startup-launcher/references/platforms/launchingnext.md +674 -0
  651. package/skills/startup-launcher/references/platforms/launchit.md +574 -0
  652. package/skills/startup-launcher/references/platforms/launchyourapp.md +677 -0
  653. package/skills/startup-launcher/references/platforms/libhunt.md +220 -0
  654. package/skills/startup-launcher/references/platforms/ltdhunt.md +221 -0
  655. package/skills/startup-launcher/references/platforms/microlaunch.md +45 -0
  656. package/skills/startup-launcher/references/platforms/openalternative.md +195 -0
  657. package/skills/startup-launcher/references/platforms/peerlist.md +56 -0
  658. package/skills/startup-launcher/references/platforms/peerpush.md +64 -0
  659. package/skills/startup-launcher/references/platforms/primeclub.md +282 -0
  660. package/skills/startup-launcher/references/platforms/productcanyon.md +190 -0
  661. package/skills/startup-launcher/references/platforms/producthunt.md +98 -0
  662. package/skills/startup-launcher/references/platforms/rankinpublic.md +315 -0
  663. package/skills/startup-launcher/references/platforms/rockethub.md +374 -0
  664. package/skills/startup-launcher/references/platforms/saasgenius.md +175 -0
  665. package/skills/startup-launcher/references/platforms/saashub.md +205 -0
  666. package/skills/startup-launcher/references/platforms/saasmantra.md +221 -0
  667. package/skills/startup-launcher/references/platforms/saaspirate.md +287 -0
  668. package/skills/startup-launcher/references/platforms/saaswarrior.md +190 -0
  669. package/skills/startup-launcher/references/platforms/saaszilla.md +194 -0
  670. package/skills/startup-launcher/references/platforms/selected.md +925 -0
  671. package/skills/startup-launcher/references/platforms/sideprojectors.md +86 -0
  672. package/skills/startup-launcher/references/platforms/softonic.md +240 -0
  673. package/skills/startup-launcher/references/platforms/sourceforge.md +251 -0
  674. package/skills/startup-launcher/references/platforms/stacksocial.md +244 -0
  675. package/skills/startup-launcher/references/platforms/startupstash.md +326 -0
  676. package/skills/startup-launcher/references/platforms/theresanaiforthat.md +253 -0
  677. package/skills/startup-launcher/references/platforms/tinylaunch.md +70 -0
  678. package/skills/startup-launcher/references/platforms/tinystartups.md +72 -0
  679. package/skills/startup-launcher/references/platforms/toolfolio.md +291 -0
  680. package/skills/startup-launcher/references/platforms/trustmrr.md +194 -0
  681. package/skills/startup-launcher/references/platforms/trylaunch.md +531 -0
  682. package/skills/startup-launcher/references/platforms/uneed.md +57 -0
  683. package/skills/startup-launcher/references/templates/asset-checklist.md +218 -0
  684. package/skills/startup-launcher/references/templates/launch-tracker.md +195 -0
  685. package/skills/startup-launcher/references/templates/product-brief.md +98 -0
  686. package/skills/summarize/.skill-meta.json +13 -0
  687. package/skills/summarize/SKILL.md +170 -0
  688. package/skills/summarize/rules/install.md +157 -0
  689. package/skills/summarize/rules/usage.md +207 -0
  690. package/skills/topical-authority/SKILL.md +307 -0
  691. package/skills/topical-authority/references/jake-ward-framework.md +201 -0
  692. package/skills/topical-authority/references/serp-clustering-algorithm.md +325 -0
  693. package/skills/topical-authority/scripts/orchestrator.js +367 -0
  694. package/skills/topical-authority/scripts/seo/analyze-competitor-coverage.js +3 -0
  695. package/skills/topical-authority/scripts/seo/audit-internal-links.js +3 -0
  696. package/skills/topical-authority/scripts/seo/build-clusters-from-serp.js +3 -0
  697. package/skills/topical-authority/scripts/seo/extract-keywords-from-forums.js +3 -0
  698. package/skills/topical-authority/scripts/seo/extract-paa-questions.js +3 -0
  699. package/skills/topical-authority/scripts/seo/fetch-serp-urls.js +3 -0
  700. package/skills/topical-authority/scripts/seo/gemini-serp-clustering.js +3 -0
  701. package/skills/topical-authority/scripts/seo/identify-content-gaps.js +3 -0
  702. package/skills/topical-authority/scripts/seo/identify-research-gaps.js +3 -0
  703. package/skills/topical-authority/scripts/seo/scrape-quora-questions.js +3 -0
  704. package/skills/topical-authority/scripts/seo/scrape-reddit-pain-points.js +3 -0
  705. package/skills/topical-authority/scripts/seo/weave-internal-links.js +3 -0
  706. package/skills/visual-style/SKILL.md +199 -0
  707. package/skills/voice-brand-alignment/SKILL.md +70 -0
  708. package/skills/voice-brand-alignment/references/ai-slop-patterns.md +405 -0
  709. package/skills/voice-brand-alignment/scripts/validation/gemini-voice-validator.js +96 -0
  710. package/skills/voice-extraction/SKILL.md +234 -0
  711. package/skills/voice-extraction/references/extraction-prompt.md +155 -0
  712. package/skills/voice-extraction/references/voice-dna-template.md +168 -0
  713. package/skills/voice-extraction/references/voice-elements.md +259 -0
  714. package/skills/voice-extraction/scripts/build-corpus.js +120 -0
  715. package/skills/voice-extraction/scripts/collect-sources.sh +168 -0
  716. package/skills/warm-outbound/SKILL.md +299 -0
  717. package/skills/warm-outbound/templates/warm-message.md +39 -0
  718. package/skills/weekly-newsletter-digest/SKILL.md +78 -0
  719. package/skills/x-playwriter/SKILL.md +428 -0
  720. package/skills/x-playwriter/scripts/x-browser.js +185 -0
  721. package/skills/x-post-generator-openclaw/SKILL.md +138 -0
  722. package/skills/x-post-generator-openclaw/scripts/generate-x-post.js +537 -0
  723. package/skills/x-posting-playwriter/SKILL.md +203 -0
  724. package/skills/x-research/SKILL.md +129 -0
  725. package/skills/x-research/x-research.sh +85 -0
  726. package/skills/youtube-summarize/SKILL.md +90 -0
  727. package/skills/youtube-summarize/scripts/youtube-summarize.sh +143 -0
  728. package/src/cli.js +349 -172
  729. package/src/harness/deepseek-adapter.js +102 -0
  730. package/src/harness/deepseek.js +225 -0
  731. package/src/harness/opencode-adapter.js +174 -0
  732. package/src/harness/pi-adapter.js +172 -0
  733. package/src/harness/registry.js +121 -0
  734. package/src/harness/telemetry.js +102 -0
  735. package/src/harness/types.js +165 -0
  736. package/src/interview.js +36 -4
  737. package/src/postinstall.js +10 -12
  738. package/templates/AGENTS.md +17 -17
  739. package/templates/ORG.md +1 -1
  740. package/templates/TOOLS.md +7 -2
  741. package/templates/opencode.json +26 -29
  742. package/wiki/doctor.md +54 -0
  743. package/wiki/inkstone.md +4 -4
  744. package/wiki/opencode.md +3 -3
  745. package/skills/curated.txt +0 -68
@@ -0,0 +1,793 @@
1
+ """
2
+ engram.py — EngramEngine: LLM-driven Observational Memory for claw-compactor.
3
+
4
+ Architecture (Layer 6 — sits on top of the 5 deterministic layers):
5
+
6
+ Layer 1 — Rule engine (compress_memory.py)
7
+ Layer 2 — Dictionary (dictionary_compress.py)
8
+ Layer 3 — Observation (observation_compressor.py) ← rule-based
9
+ Layer 4 — RLE patterns (lib/rle.py)
10
+ Layer 5 — CCP (lib/tokenizer_optimizer.py)
11
+ ──────────────────────────────────────────────────────
12
+ Layer 6 — Engram (THIS) ← LLM-driven, real-time
13
+
14
+ EngramEngine maintains three memory layers per thread:
15
+ • pending.jsonl — raw un-observed messages
16
+ • observations.md — Observer-compressed event log (append-only)
17
+ • reflections.md — Reflector-distilled long-term context
18
+
19
+ Two LLM agents run automatically when token thresholds are exceeded:
20
+ • Observer : pending messages → structured observation log
21
+ • Reflector : accumulated obs → compressed long-term reflection
22
+
23
+ Zero required dependencies: Python 3.9+.
24
+ Optional: httpx (faster HTTP), tiktoken (exact token counts).
25
+
26
+ Part of claw-compactor / Engram layer. License: MIT.
27
+ """
28
+
29
+ from __future__ import annotations
30
+
31
+ import json
32
+ import logging
33
+ import os
34
+ import time
35
+ import urllib.request
36
+ import urllib.error
37
+ from datetime import datetime, timezone
38
+ from pathlib import Path
39
+ from typing import Any, Dict, List, Optional
40
+
41
+ from lib.tokens import estimate_tokens
42
+ from lib.engram_storage import EngramStorage
43
+ from lib.engram_prompts import (
44
+ OBSERVER_SYSTEM_PROMPT,
45
+ REFLECTOR_SYSTEM_PROMPT,
46
+ OBSERVER_USER_TEMPLATE,
47
+ REFLECTOR_USER_TEMPLATE,
48
+ )
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+ # ---------------------------------------------------------------------------
53
+ # Optional httpx import
54
+ # ---------------------------------------------------------------------------
55
+ try:
56
+ import httpx as _httpx
57
+ _HTTPX_AVAILABLE = True
58
+ except ImportError:
59
+ _httpx = None # type: ignore[assignment]
60
+ _HTTPX_AVAILABLE = False
61
+
62
+
63
+ # ---------------------------------------------------------------------------
64
+ # Default configuration
65
+ # ---------------------------------------------------------------------------
66
+
67
+ DEFAULT_OBSERVER_THRESHOLD = 30_000 # tokens — pending messages before observe
68
+ DEFAULT_REFLECTOR_THRESHOLD = 40_000 # tokens — accumulated obs before reflect
69
+ DEFAULT_MODEL_ANTHROPIC = "claude-opus-4-5"
70
+ DEFAULT_MODEL_OPENAI = "gpt-4o"
71
+ DEFAULT_MAX_TOKENS = 4096
72
+ DEFAULT_ANTHROPIC_VERSION = "2023-06-01"
73
+
74
+ MAX_OBSERVER_INPUT_TOKENS = 80_000 # max tokens per Observer LLM call
75
+ MAX_REFLECTOR_INPUT_TOKENS = 80_000 # max tokens per Reflector LLM call
76
+
77
+
78
+ # ---------------------------------------------------------------------------
79
+ # EngramEngine
80
+ # ---------------------------------------------------------------------------
81
+
82
+ class EngramEngine:
83
+ """
84
+ Real-time, LLM-driven Observational Memory engine.
85
+
86
+ Usage::
87
+
88
+ engine = EngramEngine(workspace_path="/path/to/workspace")
89
+ # Add messages — auto-triggers observe/reflect when thresholds exceeded
90
+ engine.add_message("thread-1", role="user", content="Hello!")
91
+ engine.add_message("thread-1", role="assistant", content="Hi!")
92
+
93
+ # Get context to inject into a system prompt
94
+ ctx_str = engine.build_system_context("thread-1")
95
+
96
+ # Force observe/reflect manually
97
+ engine.observe("thread-1")
98
+ engine.reflect("thread-1")
99
+
100
+ Args:
101
+ workspace_path: Workspace root. Engram data is stored at
102
+ ``{workspace}/memory/engram/``.
103
+ observer_threshold: Token count of pending messages that triggers
104
+ the Observer (default 30 000).
105
+ reflector_threshold: Token count of accumulated observations that
106
+ triggers the Reflector (default 40 000).
107
+ model: LLM model identifier (auto-detected per provider).
108
+ max_tokens: Max tokens the LLM may produce per call.
109
+ anthropic_api_key: Anthropic API key (falls back to ANTHROPIC_API_KEY env).
110
+ openai_api_key: OpenAI API key (falls back to OPENAI_API_KEY env).
111
+ openai_base_url: OpenAI-compatible base URL (default: official OpenAI).
112
+ config: Raw dict to override any of the above.
113
+ """
114
+
115
+ def __init__(
116
+ self,
117
+ workspace_path: str | Path,
118
+ observer_threshold: int = DEFAULT_OBSERVER_THRESHOLD,
119
+ reflector_threshold: int = DEFAULT_REFLECTOR_THRESHOLD,
120
+ model: Optional[str] = None,
121
+ max_tokens: int = DEFAULT_MAX_TOKENS,
122
+ anthropic_api_key: Optional[str] = None,
123
+ openai_api_key: Optional[str] = None,
124
+ openai_base_url: Optional[str] = None,
125
+ config: Optional[Dict[str, Any]] = None,
126
+ ) -> None:
127
+ cfg = config or {}
128
+
129
+ self.observer_threshold = cfg.get("observer_threshold", observer_threshold)
130
+ self.reflector_threshold = cfg.get("reflector_threshold", reflector_threshold)
131
+ self.max_tokens = cfg.get("max_tokens", max_tokens)
132
+
133
+ # API keys — explicit args > config dict > env vars
134
+ self.anthropic_api_key = (
135
+ anthropic_api_key
136
+ or cfg.get("anthropic_api_key")
137
+ or os.environ.get("ANTHROPIC_API_KEY", "")
138
+ )
139
+ self.openai_api_key = (
140
+ openai_api_key
141
+ or cfg.get("openai_api_key")
142
+ or os.environ.get("OPENAI_API_KEY", "")
143
+ )
144
+ self.openai_base_url = (
145
+ openai_base_url
146
+ or cfg.get("openai_base_url")
147
+ or os.environ.get("OPENAI_BASE_URL", "https://api.openai.com")
148
+ )
149
+
150
+ # Model selection (explicit arg > config > ENGRAM_MODEL env > provider default)
151
+ _env_model = os.environ.get("ENGRAM_MODEL", "")
152
+ if model:
153
+ self.model = model
154
+ elif cfg.get("model"):
155
+ self.model = cfg["model"]
156
+ elif _env_model:
157
+ self.model = _env_model
158
+ elif self.anthropic_api_key:
159
+ self.model = cfg.get("anthropic_model", DEFAULT_MODEL_ANTHROPIC)
160
+ else:
161
+ self.model = cfg.get("openai_model", DEFAULT_MODEL_OPENAI)
162
+
163
+ self.storage = EngramStorage(Path(workspace_path))
164
+
165
+ if not self.anthropic_api_key and not self.openai_api_key:
166
+ logger.warning(
167
+ "EngramEngine: no API key configured. "
168
+ "Set ANTHROPIC_API_KEY or OPENAI_API_KEY to enable LLM compression."
169
+ )
170
+
171
+ # ------------------------------------------------------------------
172
+ # Public API
173
+ # ------------------------------------------------------------------
174
+
175
+ def add_message(
176
+ self,
177
+ thread_id: str,
178
+ role: str,
179
+ content: str,
180
+ timestamp: Optional[str] = None,
181
+ auto_observe: bool = True,
182
+ ) -> Dict[str, Any]:
183
+ """
184
+ Add a message to the thread and auto-trigger observe/reflect if needed.
185
+
186
+ Args:
187
+ thread_id: Conversation thread identifier.
188
+ role: Message role (``"user"`` / ``"assistant"`` / ``"system"``).
189
+ content: Message text content.
190
+ timestamp: Optional ``HH:MM`` or ISO timestamp string.
191
+ auto_observe: If False, skip threshold check (only write to pending).
192
+ Use False for bulk ingestion; call _check_thresholds()
193
+ manually at the end. Defaults to True (backward-compatible).
194
+
195
+ Returns:
196
+ Status dict::
197
+
198
+ {
199
+ "observed": bool,
200
+ "reflected": bool,
201
+ "pending_tokens": int,
202
+ "observation_tokens": int,
203
+ "error": str | None,
204
+ }
205
+ """
206
+ ts = timestamp or datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M")
207
+ message = {"role": role, "content": content, "timestamp": ts}
208
+ self.storage.append_message(thread_id, message)
209
+
210
+ if not auto_observe:
211
+ return {
212
+ "observed": False,
213
+ "reflected": False,
214
+ "pending_tokens": 0,
215
+ "observation_tokens": 0,
216
+ "error": None,
217
+ }
218
+
219
+ return self._check_thresholds(thread_id)
220
+
221
+ def _check_thresholds(self, thread_id: str) -> Dict[str, Any]:
222
+ """
223
+ Check Observer and Reflector thresholds and trigger as needed.
224
+
225
+ Args:
226
+ thread_id: Conversation thread identifier.
227
+
228
+ Returns:
229
+ Status dict with ``observed``, ``reflected``, ``pending_tokens``,
230
+ ``observation_tokens``, and ``error`` keys.
231
+ """
232
+ status: Dict[str, Any] = {
233
+ "observed": False,
234
+ "reflected": False,
235
+ "pending_tokens": 0,
236
+ "observation_tokens": 0,
237
+ "error": None,
238
+ }
239
+
240
+ # --- Check Observer threshold ---
241
+ pending = self.storage.read_pending(thread_id)
242
+ pending_tokens = _count_messages_tokens(pending)
243
+ status["pending_tokens"] = pending_tokens
244
+
245
+ if pending_tokens >= self.observer_threshold:
246
+ logger.info(
247
+ "Engram: Observer triggered (thread=%s, pending_tokens=%d >= %d)",
248
+ thread_id, pending_tokens, self.observer_threshold,
249
+ )
250
+ try:
251
+ self._run_observer(thread_id, pending)
252
+ status["observed"] = True
253
+ except Exception as exc:
254
+ logger.error("Engram: Observer failed: %s", exc)
255
+ status["error"] = str(exc)
256
+
257
+ # --- Check Reflector threshold (after possible observation) ---
258
+ obs_text = self.storage.read_observations(thread_id)
259
+ obs_tokens = estimate_tokens(obs_text)
260
+ status["observation_tokens"] = obs_tokens
261
+
262
+ if obs_tokens >= self.reflector_threshold:
263
+ logger.info(
264
+ "Engram: Reflector triggered (thread=%s, obs_tokens=%d >= %d)",
265
+ thread_id, obs_tokens, self.reflector_threshold,
266
+ )
267
+ try:
268
+ self._run_reflector(thread_id, obs_text)
269
+ status["reflected"] = True
270
+ except Exception as exc:
271
+ logger.error("Engram: Reflector failed: %s", exc)
272
+ if status["error"]:
273
+ status["error"] += "; " + str(exc)
274
+ else:
275
+ status["error"] = str(exc)
276
+
277
+ return status
278
+
279
+ def batch_ingest(
280
+ self,
281
+ thread_id: str,
282
+ messages: List[Dict[str, Any]],
283
+ batch_size: int = 500,
284
+ ) -> Dict[str, Any]:
285
+ """
286
+ Bulk-write messages then check thresholds once at the end.
287
+
288
+ More efficient than calling add_message() in a loop when ingesting
289
+ large amounts of historical data, because threshold checks (which
290
+ may trigger expensive LLM calls) are deferred until all messages
291
+ have been written.
292
+
293
+ Args:
294
+ thread_id: Conversation thread identifier.
295
+ messages: List of message dicts with keys ``role``, ``content``,
296
+ and optional ``timestamp``.
297
+ batch_size: Unused parameter kept for API future-proofing.
298
+
299
+ Returns:
300
+ Status dict from the final ``_check_thresholds()`` call.
301
+ """
302
+ for msg in messages:
303
+ self.add_message(
304
+ thread_id,
305
+ msg["role"],
306
+ msg["content"],
307
+ msg.get("timestamp"),
308
+ auto_observe=False,
309
+ )
310
+ # Check thresholds once after all messages are written
311
+ return self._check_thresholds(thread_id)
312
+
313
+ def observe(self, thread_id: str) -> Optional[str]:
314
+ """
315
+ Manually trigger the Observer for a thread regardless of thresholds.
316
+
317
+ Args:
318
+ thread_id: Thread identifier.
319
+
320
+ Returns:
321
+ Observation text if pending messages exist, else None.
322
+ """
323
+ pending = self.storage.read_pending(thread_id)
324
+ if not pending:
325
+ logger.info("Engram observe: no pending messages for thread=%s", thread_id)
326
+ return None
327
+ return self._run_observer(thread_id, pending)
328
+
329
+ def reflect(self, thread_id: str) -> Optional[str]:
330
+ """
331
+ Manually trigger the Reflector for a thread regardless of thresholds.
332
+
333
+ Args:
334
+ thread_id: Thread identifier.
335
+
336
+ Returns:
337
+ Reflection text if observations exist, else None.
338
+ """
339
+ obs_text = self.storage.read_observations(thread_id)
340
+ if not obs_text.strip():
341
+ logger.info("Engram reflect: no observations for thread=%s", thread_id)
342
+ return None
343
+ return self._run_reflector(thread_id, obs_text)
344
+
345
+ def get_context(self, thread_id: str) -> Dict[str, Any]:
346
+ """
347
+ Return the full three-layer memory context for a thread.
348
+
349
+ Returns:
350
+ Context dict::
351
+
352
+ {
353
+ "thread_id": str,
354
+ "observations": str,
355
+ "reflection": str,
356
+ "recent_messages": list[dict],
357
+ "stats": {
358
+ "observation_tokens": int,
359
+ "reflection_tokens": int,
360
+ "pending_tokens": int,
361
+ "total_tokens": int,
362
+ "pending_count": int,
363
+ },
364
+ "meta": dict,
365
+ }
366
+ """
367
+ observations = self.storage.read_observations(thread_id)
368
+ reflection = self.storage.read_reflection(thread_id)
369
+ recent_messages = self.storage.read_pending(thread_id)
370
+ meta = self.storage.read_meta(thread_id)
371
+
372
+ obs_tokens = estimate_tokens(observations)
373
+ ref_tokens = estimate_tokens(reflection)
374
+ pending_tokens = _count_messages_tokens(recent_messages)
375
+
376
+ return {
377
+ "thread_id": thread_id,
378
+ "observations": observations,
379
+ "reflection": reflection,
380
+ "recent_messages": recent_messages,
381
+ "stats": {
382
+ "observation_tokens": obs_tokens,
383
+ "reflection_tokens": ref_tokens,
384
+ "pending_tokens": pending_tokens,
385
+ "total_tokens": obs_tokens + ref_tokens + pending_tokens,
386
+ "pending_count": len(recent_messages),
387
+ },
388
+ "meta": meta,
389
+ }
390
+
391
+ def build_system_context(self, thread_id: str) -> str:
392
+ """
393
+ Build a compact, injectable system-context string for this thread.
394
+
395
+ Includes (in priority order):
396
+ 1. Reflection (long-term context, if present)
397
+ 2. Recent observations (up to ~200 lines / ~8K tokens)
398
+ 3. Token budget summary comment
399
+
400
+ Args:
401
+ thread_id: Thread identifier.
402
+
403
+ Returns:
404
+ Formatted string ready to prepend to a system prompt. Empty string
405
+ if there is no context at all.
406
+ """
407
+ ctx = self.get_context(thread_id)
408
+ parts: List[str] = []
409
+
410
+ if ctx["reflection"].strip():
411
+ parts.append("## Long-Term Memory (Reflections)\n" + ctx["reflection"])
412
+
413
+ if ctx["observations"].strip():
414
+ obs_lines = ctx["observations"].splitlines()
415
+ if len(obs_lines) > 200:
416
+ obs_lines = obs_lines[-200:]
417
+ parts.append("## Recent Observations\n" + "\n".join(obs_lines))
418
+
419
+ if not parts:
420
+ return ""
421
+
422
+ total = ctx["stats"]["total_tokens"]
423
+ parts.append(f"\n<!-- engram_tokens: {total} -->")
424
+ return "\n\n".join(parts)
425
+
426
+ # ------------------------------------------------------------------
427
+ # Internal helpers
428
+ # ------------------------------------------------------------------
429
+
430
+ def _run_observer(self, thread_id: str, messages: List[dict]) -> str:
431
+ """Run Observer LLM, persist result, clear pending queue.
432
+
433
+ If messages exceed MAX_OBSERVER_INPUT_TOKENS, process in batches.
434
+ """
435
+ total_tokens = _count_messages_tokens(messages)
436
+
437
+ if total_tokens <= MAX_OBSERVER_INPUT_TOKENS:
438
+ # Normal path — single call
439
+ observation = self._llm_observe(messages)
440
+ ts = _now_utc()
441
+ self.storage.append_observation(thread_id, observation, timestamp=ts)
442
+ self.storage.clear_pending(thread_id)
443
+ logger.debug(
444
+ "Engram: Observer done (thread=%s, chars=%d)", thread_id, len(observation)
445
+ )
446
+ return observation
447
+
448
+ # Batch path — split messages into chunks that fit within the token limit
449
+ logger.info(
450
+ "Engram: Observer batching (thread=%s, total_tokens=%d, max=%d)",
451
+ thread_id, total_tokens, MAX_OBSERVER_INPUT_TOKENS,
452
+ )
453
+
454
+ all_observations: List[str] = []
455
+ batch_start = 0
456
+
457
+ while batch_start < len(messages):
458
+ # Build a batch that fits within the token limit
459
+ batch: List[dict] = []
460
+ batch_tokens = 0
461
+ next_start = batch_start
462
+
463
+ for i in range(batch_start, len(messages)):
464
+ msg = messages[i]
465
+ msg_tokens = _count_messages_tokens([msg])
466
+ if batch_tokens + msg_tokens > MAX_OBSERVER_INPUT_TOKENS and batch:
467
+ # This message would overflow; stop here
468
+ break
469
+ batch.append(msg)
470
+ batch_tokens += msg_tokens
471
+ next_start = i + 1
472
+
473
+ if not batch:
474
+ # Single message exceeds limit — include it anyway to avoid infinite loop
475
+ batch = [messages[batch_start]]
476
+ next_start = batch_start + 1
477
+
478
+ logger.info(
479
+ "Engram: Observer batch %d (thread=%s, msgs=%d, tokens=%d)",
480
+ len(all_observations) + 1, thread_id, len(batch), batch_tokens,
481
+ )
482
+
483
+ observation = self._llm_observe(batch)
484
+ all_observations.append(observation)
485
+ batch_start = next_start
486
+
487
+ # Combine all batch observations
488
+ combined = "\n\n---\n\n".join(all_observations)
489
+ ts = _now_utc()
490
+ self.storage.append_observation(thread_id, combined, timestamp=ts)
491
+ self.storage.clear_pending(thread_id)
492
+
493
+ logger.debug(
494
+ "Engram: Observer done (thread=%s, batches=%d, chars=%d)",
495
+ thread_id, len(all_observations), len(combined),
496
+ )
497
+ return combined
498
+
499
+ def _run_reflector(self, thread_id: str, observations: str) -> str:
500
+ """Run Reflector LLM, persist result (overwrites previous reflection).
501
+
502
+ If observations exceed MAX_REFLECTOR_INPUT_TOKENS, truncate to the most
503
+ recent content (tail) to stay within the LLM context window.
504
+ """
505
+ obs_tokens = estimate_tokens(observations)
506
+
507
+ if obs_tokens > MAX_REFLECTOR_INPUT_TOKENS:
508
+ # Keep the most recent observations (tail)
509
+ lines = observations.splitlines()
510
+ truncated: List[str] = []
511
+ running_tokens = 0
512
+ for line in reversed(lines):
513
+ line_tokens = estimate_tokens(line)
514
+ if running_tokens + line_tokens > MAX_REFLECTOR_INPUT_TOKENS:
515
+ break
516
+ truncated.append(line)
517
+ running_tokens += line_tokens
518
+ observations = "\n".join(reversed(truncated))
519
+ logger.info(
520
+ "Engram: Reflector input truncated (thread=%s, %d -> %d tokens)",
521
+ thread_id, obs_tokens, running_tokens,
522
+ )
523
+
524
+ reflection = self._llm_reflect(observations)
525
+ ts = _now_utc()
526
+ self.storage.write_reflection(thread_id, reflection, timestamp=ts)
527
+ logger.debug(
528
+ "Engram: Reflector done (thread=%s, chars=%d)", thread_id, len(reflection)
529
+ )
530
+ return reflection
531
+
532
+ def _llm_observe(self, messages: List[dict]) -> str:
533
+ """Format messages and call the Observer LLM."""
534
+ messages_text = _messages_to_text(messages)
535
+ current_dt = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
536
+ user_content = OBSERVER_USER_TEMPLATE.format(
537
+ current_datetime=current_dt,
538
+ messages_text=messages_text,
539
+ )
540
+ return self._call_llm(OBSERVER_SYSTEM_PROMPT, user_content)
541
+
542
+ def _llm_reflect(self, observations: str) -> str:
543
+ """Format observations and call the Reflector LLM."""
544
+ current_dt = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
545
+ user_content = REFLECTOR_USER_TEMPLATE.format(
546
+ current_datetime=current_dt,
547
+ observations_text=observations,
548
+ )
549
+ return self._call_llm(REFLECTOR_SYSTEM_PROMPT, user_content)
550
+
551
+ def _call_llm(self, system: str, user: str) -> str:
552
+ """
553
+ Call LLM API. Prefers Anthropic if key available, else OpenAI-compatible.
554
+
555
+ Args:
556
+ system: System prompt.
557
+ user: User message content.
558
+
559
+ Returns:
560
+ Assistant response text.
561
+
562
+ Raises:
563
+ RuntimeError: If no API key is configured.
564
+ Exception: On HTTP or parsing errors.
565
+ """
566
+ if self.anthropic_api_key:
567
+ return self._call_anthropic(system, user)
568
+ if self.openai_api_key:
569
+ return self._call_openai_compatible(system, user)
570
+ raise RuntimeError(
571
+ "EngramEngine: no API key configured. "
572
+ "Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable."
573
+ )
574
+
575
+ def _call_anthropic(self, system: str, user: str) -> str:
576
+ """Call the Anthropic Messages API."""
577
+ url = "https://api.anthropic.com/v1/messages"
578
+ headers = {
579
+ "x-api-key": self.anthropic_api_key,
580
+ "anthropic-version": DEFAULT_ANTHROPIC_VERSION,
581
+ "content-type": "application/json",
582
+ }
583
+ body = {
584
+ "model": self.model,
585
+ "max_tokens": self.max_tokens,
586
+ "system": system,
587
+ "messages": [{"role": "user", "content": user}],
588
+ }
589
+ data = _http_post(url, headers, body)
590
+ content = data.get("content", [])
591
+ for block in content:
592
+ if block.get("type") == "text":
593
+ return block["text"]
594
+ raise ValueError(f"Engram: no text content in Anthropic response: {data}")
595
+
596
+ def _call_openai_compatible(self, system: str, user: str) -> str:
597
+ """Call an OpenAI-compatible chat completions endpoint."""
598
+ base = self.openai_base_url.rstrip("/")
599
+ url = f"{base}/v1/chat/completions"
600
+ headers = {
601
+ "Authorization": f"Bearer {self.openai_api_key}",
602
+ "content-type": "application/json",
603
+ }
604
+ body = {
605
+ "model": self.model,
606
+ "max_tokens": self.max_tokens,
607
+ "messages": [
608
+ {"role": "system", "content": system},
609
+ {"role": "user", "content": user},
610
+ ],
611
+ }
612
+ data = _http_post(url, headers, body)
613
+ try:
614
+ return data["choices"][0]["message"]["content"]
615
+ except (KeyError, IndexError) as exc:
616
+ raise ValueError(
617
+ f"Engram: unexpected OpenAI response structure: {data}"
618
+ ) from exc
619
+
620
+
621
+ # ---------------------------------------------------------------------------
622
+ # HTTP helper (httpx preferred, urllib fallback)
623
+ # ---------------------------------------------------------------------------
624
+
625
+ # HTTP status codes that should not be retried (client errors)
626
+ _NO_RETRY_CODES = {400, 401, 403}
627
+ # HTTP status codes that are transient and worth retrying
628
+ _RETRY_CODES = {429, 500, 502, 503, 504}
629
+ # Exception types that indicate transient network issues
630
+ _RETRY_EXCEPTIONS = (ConnectionError, ConnectionResetError, TimeoutError,
631
+ urllib.error.URLError)
632
+
633
+
634
+ def _http_post(url: str, headers: dict, body: dict, max_retries: int = 3) -> dict:
635
+ """
636
+ POST JSON body to *url* and return parsed JSON response.
637
+
638
+ Retries on transient HTTP errors (429, 500, 502, 503, 504) and network
639
+ exceptions using exponential back-off: 2, 4, 8 seconds between attempts.
640
+ Non-retriable errors (400, 401, 403) are raised immediately.
641
+
642
+ Args:
643
+ url: Target URL.
644
+ headers: HTTP headers dict.
645
+ body: Request body (will be JSON-serialised).
646
+ max_retries: Maximum number of retry attempts (default 3).
647
+
648
+ Returns:
649
+ Parsed JSON response dict.
650
+
651
+ Raises:
652
+ RuntimeError: On non-retriable HTTP errors or after exhausting retries.
653
+ """
654
+ payload = json.dumps(body, ensure_ascii=False).encode("utf-8")
655
+
656
+ if _HTTPX_AVAILABLE and _httpx is not None:
657
+ last_exc: Optional[Exception] = None
658
+ for attempt in range(max_retries + 1):
659
+ try:
660
+ with _httpx.Client(timeout=120.0) as client:
661
+ resp = client.post(url, headers=headers, content=payload)
662
+ if resp.status_code in _NO_RETRY_CODES:
663
+ raise RuntimeError(
664
+ f"Engram HTTP {resp.status_code} from {url}: {resp.text}"
665
+ )
666
+ if resp.status_code in _RETRY_CODES and attempt < max_retries:
667
+ delay = 2 ** (attempt + 1)
668
+ logger.warning(
669
+ "Engram HTTP %d, retry %d/%d in %ds…",
670
+ resp.status_code, attempt + 1, max_retries, delay,
671
+ )
672
+ time.sleep(delay)
673
+ last_exc = RuntimeError(
674
+ f"Engram HTTP {resp.status_code} from {url}"
675
+ )
676
+ continue
677
+ resp.raise_for_status()
678
+ return resp.json()
679
+ except _RETRY_EXCEPTIONS as exc:
680
+ last_exc = exc
681
+ if attempt < max_retries:
682
+ delay = 2 ** (attempt + 1)
683
+ logger.warning(
684
+ "Engram network error (%s), retry %d/%d in %ds…",
685
+ exc, attempt + 1, max_retries, delay,
686
+ )
687
+ time.sleep(delay)
688
+ else:
689
+ raise
690
+ raise last_exc or RuntimeError(f"Engram: max retries exceeded for {url}")
691
+
692
+ # Fallback: stdlib urllib
693
+ last_exc2: Optional[Exception] = None
694
+ for attempt in range(max_retries + 1):
695
+ req = urllib.request.Request(url, data=payload, headers=headers, method="POST")
696
+ try:
697
+ with urllib.request.urlopen(req, timeout=120) as resp:
698
+ raw = resp.read().decode("utf-8")
699
+ return json.loads(raw)
700
+ except urllib.error.HTTPError as exc:
701
+ if exc.code in _NO_RETRY_CODES:
702
+ body_text = exc.read().decode("utf-8", errors="replace")
703
+ raise RuntimeError(
704
+ f"Engram HTTP {exc.code} from {url}: {body_text}"
705
+ ) from exc
706
+ if exc.code in _RETRY_CODES and attempt < max_retries:
707
+ delay = 2 ** (attempt + 1)
708
+ logger.warning(
709
+ "Engram HTTP %d, retry %d/%d in %ds…",
710
+ exc.code, attempt + 1, max_retries, delay,
711
+ )
712
+ time.sleep(delay)
713
+ last_exc2 = exc
714
+ continue
715
+ body_text = exc.read().decode("utf-8", errors="replace")
716
+ raise RuntimeError(
717
+ f"Engram HTTP {exc.code} from {url}: {body_text}"
718
+ ) from exc
719
+ except _RETRY_EXCEPTIONS as exc:
720
+ last_exc2 = exc
721
+ if attempt < max_retries:
722
+ delay = 2 ** (attempt + 1)
723
+ logger.warning(
724
+ "Engram network error (%s), retry %d/%d in %ds…",
725
+ exc, attempt + 1, max_retries, delay,
726
+ )
727
+ time.sleep(delay)
728
+ else:
729
+ raise
730
+ raise last_exc2 or RuntimeError(f"Engram: max retries exceeded for {url}")
731
+
732
+
733
+ # ---------------------------------------------------------------------------
734
+ # Utility functions
735
+ # ---------------------------------------------------------------------------
736
+
737
+ def _now_utc() -> str:
738
+ return datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
739
+
740
+
741
+ def _count_messages_tokens(messages: List[dict]) -> int:
742
+ """Estimate token count for a list of message dicts."""
743
+ total = 0
744
+ for msg in messages:
745
+ content = msg.get("content", "")
746
+ if isinstance(content, list):
747
+ for block in content:
748
+ if isinstance(block, dict):
749
+ total += estimate_tokens(block.get("text", ""))
750
+ total += estimate_tokens(str(block.get("input", "")))
751
+ else:
752
+ total += estimate_tokens(str(content))
753
+ total += 4 # per-message overhead
754
+ return total
755
+
756
+
757
+ def _messages_to_text(messages: List[dict]) -> str:
758
+ """Serialise a list of message dicts into a human-readable text block."""
759
+ lines: List[str] = []
760
+ for i, msg in enumerate(messages):
761
+ role = msg.get("role", "unknown").upper()
762
+ ts = msg.get("timestamp", "")
763
+ ts_str = f" [{ts}]" if ts else ""
764
+ content = msg.get("content", "")
765
+
766
+ if isinstance(content, list):
767
+ parts: List[str] = []
768
+ for block in content:
769
+ if isinstance(block, dict):
770
+ btype = block.get("type", "")
771
+ if btype == "text":
772
+ parts.append(block.get("text", ""))
773
+ elif btype == "tool_use":
774
+ parts.append(
775
+ f"[tool_call: {block.get('name')} "
776
+ f"input={json.dumps(block.get('input', {}), ensure_ascii=False)[:200]}]"
777
+ )
778
+ elif btype == "tool_result":
779
+ raw = block.get("content", "")
780
+ if isinstance(raw, list):
781
+ raw = " ".join(
782
+ b.get("text", "") for b in raw if isinstance(b, dict)
783
+ )
784
+ parts.append(f"[tool_result: {str(raw)[:500]}]")
785
+ else:
786
+ parts.append(str(block))
787
+ content_str = "\n".join(parts)
788
+ else:
789
+ content_str = str(content)
790
+
791
+ lines.append(f"[{i + 1}] {role}{ts_str}:\n{content_str}\n")
792
+
793
+ return "\n".join(lines)