geneseed 2.0.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 (337) hide show
  1. package/CHANGELOG.md +938 -0
  2. package/DESIGN.md +1423 -0
  3. package/LICENSE +21 -0
  4. package/QUICKSTART.md +48 -0
  5. package/README.md +336 -0
  6. package/SETUP.md +1027 -0
  7. package/SHIPPED.md +70 -0
  8. package/adapters/bob/README.md +100 -0
  9. package/adapters/claude-code/README.md +101 -0
  10. package/adapters/claude-code/settings.json +47 -0
  11. package/adapters/claude-code/skills/geneseed/SKILL.md +72 -0
  12. package/adapters/copilot/README.md +76 -0
  13. package/adapters/opencode/GLOBAL-HARNESS-SPEC.md +434 -0
  14. package/adapters/opencode/HOW-OPENCODE-LOADS.md +158 -0
  15. package/adapters/opencode/README.md +582 -0
  16. package/adapters/opencode/agents/orchestrator.md +25 -0
  17. package/adapters/opencode/opencode.json +44 -0
  18. package/adapters/opencode/plugins/geneseed-activity.js +430 -0
  19. package/adapters/opencode/plugins/geneseed-context.js +876 -0
  20. package/adapters/opencode/plugins/geneseed-guard.js +290 -0
  21. package/adapters/opencode/plugins/geneseed-learn.js +396 -0
  22. package/adapters/opencode/plugins/geneseed-notify.js +142 -0
  23. package/adapters/opencode/plugins/geneseed-ponytail.js +148 -0
  24. package/adapters/opencode/plugins/geneseed-workflow.js +183 -0
  25. package/adapters/opencode/workflows/_runtime.js +277 -0
  26. package/adapters/opencode/workflows/council.js +64 -0
  27. package/adapters/opencode/workflows/dispatch.js +89 -0
  28. package/adapters/opencode/workflows/research-plan-implement.js +43 -0
  29. package/adapters/opencode/workflows/review.js +57 -0
  30. package/bin/geneseed-cli.mjs +412 -0
  31. package/bin/geneseed-hook.mjs +129 -0
  32. package/bin/geneseed.mjs +1086 -0
  33. package/docs/declined.md +149 -0
  34. package/docs/limits.md +270 -0
  35. package/docs/opencode-plugin-setup.md +64 -0
  36. package/docs/token-footprint.md +68 -0
  37. package/docs/web/_groups.json +45 -0
  38. package/docs/web/about.md +6 -0
  39. package/docs/web/adapters-claude-code.md +8 -0
  40. package/docs/web/adapters-opencode-loads.md +8 -0
  41. package/docs/web/adapters-opencode-spec.md +8 -0
  42. package/docs/web/adapters-opencode.md +8 -0
  43. package/docs/web/agents.md +8 -0
  44. package/docs/web/authoring.md +11 -0
  45. package/docs/web/autostart.md +9 -0
  46. package/docs/web/claude-hooks.md +36 -0
  47. package/docs/web/cli.md +6 -0
  48. package/docs/web/collaboration.md +27 -0
  49. package/docs/web/configure-wiki.md +9 -0
  50. package/docs/web/design.md +7 -0
  51. package/docs/web/env-knobs.md +9 -0
  52. package/docs/web/exclusions.md +26 -0
  53. package/docs/web/first-session.md +28 -0
  54. package/docs/web/footprint.md +31 -0
  55. package/docs/web/foreman-mode.md +33 -0
  56. package/docs/web/glossary.md +6 -0
  57. package/docs/web/harnesses.md +28 -0
  58. package/docs/web/headless.md +9 -0
  59. package/docs/web/ingest-docs.md +9 -0
  60. package/docs/web/install-paths.md +9 -0
  61. package/docs/web/install-quick.md +35 -0
  62. package/docs/web/lsp-overview.md +37 -0
  63. package/docs/web/mcp-claude-code.md +10 -0
  64. package/docs/web/mcp-filesystem.md +9 -0
  65. package/docs/web/mcp-gitlab.md +9 -0
  66. package/docs/web/mcp-markitdown.md +9 -0
  67. package/docs/web/mcp-overview.md +34 -0
  68. package/docs/web/mcp-trouble.md +9 -0
  69. package/docs/web/mcp-verify.md +9 -0
  70. package/docs/web/memory.md +7 -0
  71. package/docs/web/migrate.md +39 -0
  72. package/docs/web/model.md +20 -0
  73. package/docs/web/notebook.md +7 -0
  74. package/docs/web/pipelines.md +24 -0
  75. package/docs/web/plugin-activity.md +23 -0
  76. package/docs/web/plugin-context.md +26 -0
  77. package/docs/web/plugin-guard.md +24 -0
  78. package/docs/web/plugin-learn.md +27 -0
  79. package/docs/web/plugin-notify.md +24 -0
  80. package/docs/web/plugin-ponytail.md +23 -0
  81. package/docs/web/plugin-setup.md +7 -0
  82. package/docs/web/plugin-workflow.md +24 -0
  83. package/docs/web/plugins.md +17 -0
  84. package/docs/web/project-context.md +9 -0
  85. package/docs/web/rules.md +8 -0
  86. package/docs/web/run-anywhere.md +9 -0
  87. package/docs/web/self-improve.md +8 -0
  88. package/docs/web/setup-choices.md +39 -0
  89. package/docs/web/skills.md +8 -0
  90. package/docs/web/themes-author.md +8 -0
  91. package/docs/web/themes.md +9 -0
  92. package/docs/web/token-footprint.md +7 -0
  93. package/docs/web/trouble.md +38 -0
  94. package/docs/web/upgrade.md +9 -0
  95. package/docs/web/verify.md +30 -0
  96. package/docs/web/wiki.md +7 -0
  97. package/docs/web/worktree.md +10 -0
  98. package/docs/web-ui.md +144 -0
  99. package/docs/wiki.md +43 -0
  100. package/geneseed +39 -0
  101. package/geneseed.cmd +34 -0
  102. package/harness.config.json +6 -0
  103. package/js/anim.mjs +326 -0
  104. package/js/catalog.mjs +112 -0
  105. package/js/checkout.mjs +88 -0
  106. package/js/cli-table.json +1034 -0
  107. package/js/cli.mjs +498 -0
  108. package/js/diff.mjs +384 -0
  109. package/js/doctor.mjs +1364 -0
  110. package/js/emit.mjs +1373 -0
  111. package/js/excludes.mjs +271 -0
  112. package/js/generate.mjs +379 -0
  113. package/js/hooks.mjs +1026 -0
  114. package/js/hosts.mjs +253 -0
  115. package/js/installs.mjs +378 -0
  116. package/js/inventory.mjs +175 -0
  117. package/js/lib/fs.mjs +913 -0
  118. package/js/lib/proc.mjs +28 -0
  119. package/js/lib/udiff.mjs +275 -0
  120. package/js/link.mjs +286 -0
  121. package/js/mcp.mjs +335 -0
  122. package/js/memory.mjs +108 -0
  123. package/js/menu.mjs +118 -0
  124. package/js/migrate.mjs +251 -0
  125. package/js/native.mjs +426 -0
  126. package/js/opencode.mjs +325 -0
  127. package/js/registry.mjs +110 -0
  128. package/js/render.mjs +282 -0
  129. package/js/settings.mjs +924 -0
  130. package/js/setup.mjs +492 -0
  131. package/js/status.mjs +281 -0
  132. package/js/themes.mjs +195 -0
  133. package/js/tui.mjs +444 -0
  134. package/js/uninstall.mjs +1137 -0
  135. package/js/update.mjs +910 -0
  136. package/js/web/actions.mjs +868 -0
  137. package/js/web/activity.mjs +284 -0
  138. package/js/web/api.mjs +873 -0
  139. package/js/web/docs.mjs +531 -0
  140. package/js/web/graph.mjs +0 -0
  141. package/js/web/jobs.mjs +480 -0
  142. package/js/web/server.mjs +1135 -0
  143. package/package.json +54 -0
  144. package/registry.json +474 -0
  145. package/src/AGENT.md.tmpl +390 -0
  146. package/src/agents/_template.md +76 -0
  147. package/src/agents/advocate.md +36 -0
  148. package/src/agents/architect.md +55 -0
  149. package/src/agents/developer.md +66 -0
  150. package/src/agents/docs.md +54 -0
  151. package/src/agents/empiricist.md +39 -0
  152. package/src/agents/explorer.md +54 -0
  153. package/src/agents/framer.md +36 -0
  154. package/src/agents/historian.md +51 -0
  155. package/src/agents/operator.md +37 -0
  156. package/src/agents/pragmatist.md +37 -0
  157. package/src/agents/reviewer.md +52 -0
  158. package/src/agents/security.md +57 -0
  159. package/src/agents/skeptic.md +48 -0
  160. package/src/agents/steward.md +36 -0
  161. package/src/agents/tester.md +54 -0
  162. package/src/agents/user-advocate.md +36 -0
  163. package/src/agents/visionary.md +36 -0
  164. package/src/laws/universal.md +387 -0
  165. package/src/memory/README.md +109 -0
  166. package/src/memory/gitignore +6 -0
  167. package/src/modes/README.md +26 -0
  168. package/src/modes/direct.md +2 -0
  169. package/src/modes/foreman.md +19 -0
  170. package/src/notebook/README.md +39 -0
  171. package/src/notebook/gitignore +7 -0
  172. package/src/postures/README.md +31 -0
  173. package/src/postures/artisan.md +14 -0
  174. package/src/postures/assistant.md +12 -0
  175. package/src/postures/expert.md +11 -0
  176. package/src/postures/mentor.md +11 -0
  177. package/src/postures/peer.md +12 -0
  178. package/src/skills/_template.md +47 -0
  179. package/src/skills/brainstorm.md +28 -0
  180. package/src/skills/clarify.md +28 -0
  181. package/src/skills/codebase-design.md +44 -0
  182. package/src/skills/commit.md +48 -0
  183. package/src/skills/council.md +34 -0
  184. package/src/skills/crash-course.md +28 -0
  185. package/src/skills/daydream/.claude-plugin/plugin.json +9 -0
  186. package/src/skills/daydream/SKILL.md +74 -0
  187. package/src/skills/daydream/VENDOR.md +25 -0
  188. package/src/skills/daydream/critic-prompt.md +38 -0
  189. package/src/skills/daydream/instructions.md +422 -0
  190. package/src/skills/daydream/synthesizer-prompt.md +41 -0
  191. package/src/skills/debug.md +37 -0
  192. package/src/skills/decode.md +28 -0
  193. package/src/skills/develop.md +29 -0
  194. package/src/skills/document-project.md +79 -0
  195. package/src/skills/domain-modeling.md +38 -0
  196. package/src/skills/drill.md +28 -0
  197. package/src/skills/feynman.md +26 -0
  198. package/src/skills/forge-mcp.md +48 -0
  199. package/src/skills/fresh-eyes.md +29 -0
  200. package/src/skills/frontend-design.md +58 -0
  201. package/src/skills/gap-detector.md +27 -0
  202. package/src/skills/geneseed-code-review.md +33 -0
  203. package/src/skills/geneseed.md +29 -0
  204. package/src/skills/git-archaeology.md +47 -0
  205. package/src/skills/git-rescue.md +68 -0
  206. package/src/skills/handoff.md +29 -0
  207. package/src/skills/herdr.md +164 -0
  208. package/src/skills/ingest.md +49 -0
  209. package/src/skills/learning-path.md +26 -0
  210. package/src/skills/migrate.md +45 -0
  211. package/src/skills/opencode-theme.md +52 -0
  212. package/src/skills/parallel-agents.md +28 -0
  213. package/src/skills/pipeline.md +52 -0
  214. package/src/skills/plan.md +45 -0
  215. package/src/skills/ponytail.md +29 -0
  216. package/src/skills/profile.md +58 -0
  217. package/src/skills/prose.md +42 -0
  218. package/src/skills/prototype.md +44 -0
  219. package/src/skills/react-view-transitions/AGENTS.md +955 -0
  220. package/src/skills/react-view-transitions/README.md +42 -0
  221. package/src/skills/react-view-transitions/SKILL.md +320 -0
  222. package/src/skills/react-view-transitions/VENDOR.md +16 -0
  223. package/src/skills/react-view-transitions/metadata.json +12 -0
  224. package/src/skills/react-view-transitions/references/css-recipes.md +242 -0
  225. package/src/skills/react-view-transitions/references/implementation.md +182 -0
  226. package/src/skills/react-view-transitions/references/nextjs.md +176 -0
  227. package/src/skills/react-view-transitions/references/patterns.md +262 -0
  228. package/src/skills/refactor.md +32 -0
  229. package/src/skills/release.md +43 -0
  230. package/src/skills/repo-map.md +36 -0
  231. package/src/skills/research.md +42 -0
  232. package/src/skills/review-response.md +36 -0
  233. package/src/skills/roast-me.md +28 -0
  234. package/src/skills/rule.md +100 -0
  235. package/src/skills/ship.md +49 -0
  236. package/src/skills/tdd.md +31 -0
  237. package/src/skills/tickets.md +44 -0
  238. package/src/skills/token-report/SKILL.md +76 -0
  239. package/src/skills/token-report/VENDOR.md +23 -0
  240. package/src/skills/token-report/scripts/token_report.mjs +1301 -0
  241. package/src/skills/wayfinder.md +49 -0
  242. package/src/skills/wiki.md +68 -0
  243. package/src/skills/workflow.md +38 -0
  244. package/themes/README.md +69 -0
  245. package/themes/_TEMPLATE.json +147 -0
  246. package/themes/biker.json +147 -0
  247. package/themes/commentator.json +147 -0
  248. package/themes/cyberpunk.json +147 -0
  249. package/themes/gamer.json +147 -0
  250. package/themes/imperial.json +147 -0
  251. package/themes/joker.json +147 -0
  252. package/themes/marvin.json +147 -0
  253. package/themes/mean.json +147 -0
  254. package/themes/military.json +147 -0
  255. package/themes/neutral.json +147 -0
  256. package/themes/opencode/README.md +58 -0
  257. package/themes/opencode/catppuccin.json +27 -0
  258. package/themes/opencode/dracula.json +27 -0
  259. package/themes/opencode/everforest.json +27 -0
  260. package/themes/opencode/gruvbox.json +27 -0
  261. package/themes/opencode/kanagawa.json +27 -0
  262. package/themes/opencode/neon.json +27 -0
  263. package/themes/opencode/nord.json +27 -0
  264. package/themes/opencode/rosepine.json +27 -0
  265. package/themes/opencode/tokyonight.json +27 -0
  266. package/themes/pirate.json +147 -0
  267. package/themes/sports.json +147 -0
  268. package/themes/verstappen.json +147 -0
  269. package/themes/wizard.json +147 -0
  270. package/web/dist/assets/About-DX1-VTBP.js +1 -0
  271. package/web/dist/assets/Activity-Dp9NaXOn.js +1 -0
  272. package/web/dist/assets/ActivityDetail-HpOBtrXS.js +1 -0
  273. package/web/dist/assets/Diff-Ct4G3Se8.js +5 -0
  274. package/web/dist/assets/Doctor-DGjkZFuA.js +1 -0
  275. package/web/dist/assets/Graph-b8o-S6kv.js +1 -0
  276. package/web/dist/assets/Harnesses-gr3-aHBF.js +1 -0
  277. package/web/dist/assets/Laws-DTwF5tTC.js +1 -0
  278. package/web/dist/assets/Library-BEZscyaQ.js +1 -0
  279. package/web/dist/assets/Markdown-k_LSLBGq.js +1 -0
  280. package/web/dist/assets/Profile-DydukTxP.js +1 -0
  281. package/web/dist/assets/Rules-CIRG4Ldt.js +1 -0
  282. package/web/dist/assets/Skills-Buoi1IBr.js +1 -0
  283. package/web/dist/assets/StatusBadge-CE_AJttl.js +1 -0
  284. package/web/dist/assets/Themes-CI4o3gJC.js +2 -0
  285. package/web/dist/assets/activity-BCW7e6Cy.js +1 -0
  286. package/web/dist/assets/audiowide-latin-400-normal-6GFCX7ni.woff2 +0 -0
  287. package/web/dist/assets/geist-mono-latin-400-normal-DKaoCDn5.woff2 +0 -0
  288. package/web/dist/assets/geist-mono-latin-500-normal-C3sF8Y1B.woff2 +0 -0
  289. package/web/dist/assets/geist-mono-latin-600-normal-BHzjB6_C.woff2 +0 -0
  290. package/web/dist/assets/hanken-grotesk-latin-400-italic-Bserb8X5.woff2 +0 -0
  291. package/web/dist/assets/hanken-grotesk-latin-400-normal-BG6hkEXj.woff2 +0 -0
  292. package/web/dist/assets/hanken-grotesk-latin-500-italic-BGfwwhek.woff2 +0 -0
  293. package/web/dist/assets/hanken-grotesk-latin-500-normal-DrDcrrxK.woff2 +0 -0
  294. package/web/dist/assets/hanken-grotesk-latin-600-normal-CIXX6EOa.woff2 +0 -0
  295. package/web/dist/assets/hanken-grotesk-latin-700-normal-CeQ8H3UY.woff2 +0 -0
  296. package/web/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
  297. package/web/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
  298. package/web/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
  299. package/web/dist/assets/ibm-plex-serif-latin-400-normal-BIGslYFI.woff2 +0 -0
  300. package/web/dist/assets/ibm-plex-serif-latin-500-normal-REKAfBVG.woff2 +0 -0
  301. package/web/dist/assets/ibm-plex-serif-latin-600-normal-DAxitmSu.woff2 +0 -0
  302. package/web/dist/assets/index-B1PIx7RM.js +1 -0
  303. package/web/dist/assets/index-BnTQUSUz.js +12 -0
  304. package/web/dist/assets/index-Ck2iCdaC.js +2 -0
  305. package/web/dist/assets/index-DUCsDv7z.css +1 -0
  306. package/web/dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
  307. package/web/dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
  308. package/web/dist/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
  309. package/web/dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
  310. package/web/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
  311. package/web/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
  312. package/web/dist/assets/jetbrains-mono-latin-600-normal-C8RAYTDA.woff2 +0 -0
  313. package/web/dist/assets/marked.esm-JKvyS0Pp.js +46 -0
  314. package/web/dist/assets/oswald-latin-400-normal-BAFo8sP8.woff2 +0 -0
  315. package/web/dist/assets/oswald-latin-500-normal-B-eyT0Dw.woff2 +0 -0
  316. package/web/dist/assets/oswald-latin-600-normal-plFmSr5g.woff2 +0 -0
  317. package/web/dist/assets/oswald-latin-700-normal-vy6hmKSr.woff2 +0 -0
  318. package/web/dist/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
  319. package/web/dist/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
  320. package/web/dist/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
  321. package/web/dist/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
  322. package/web/dist/assets/react-DOpiTn5v.js +32 -0
  323. package/web/dist/assets/roman-DkYN0LX9.js +1 -0
  324. package/web/dist/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
  325. package/web/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
  326. package/web/dist/assets/space-grotesk-latin-600-normal-DjKNqYRj.woff2 +0 -0
  327. package/web/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
  328. package/web/dist/assets/space-mono-latin-400-italic-YylcN9Ay.woff2 +0 -0
  329. package/web/dist/assets/space-mono-latin-400-normal-Rg4St2Dn.woff2 +0 -0
  330. package/web/dist/assets/space-mono-latin-700-italic-vNvENeTh.woff2 +0 -0
  331. package/web/dist/assets/space-mono-latin-700-normal-mWgeinG7.woff2 +0 -0
  332. package/web/dist/icon-maskable.svg +10 -0
  333. package/web/dist/icon.svg +8 -0
  334. package/web/dist/index.html +21 -0
  335. package/web/dist/manifest.webmanifest +14 -0
  336. package/web/dist/sw.js +40 -0
  337. package/web/src/pages/Laws.jsx +230 -0
@@ -0,0 +1,434 @@
1
+ # Global Harness + Convention-Glob Context — Spec
2
+
3
+ Status: **implemented** (build emitter + context plugin v2 landed; docs synced).
4
+ Target adapter: OpenCode. A *second deployment mode* ("everything global, zero
5
+ per-repo files") plus the context-discovery redesign that makes it safe.
6
+
7
+ It does **not** replace the portable bundle or the Claude Code adapter. The
8
+ factory (`Geneseed/`) stays the single source of truth; this adds a way to render
9
+ it straight into OpenCode's global config dir and discover each repo's docs by
10
+ convention instead of by a committed `context.json`.
11
+
12
+ ---
13
+
14
+ ## 0. Why this exists (the principle it must not break)
15
+
16
+ The harness enforces project context by **injection, not instruction** — eager
17
+ docs are put *in context before turn 1*, never "left to agent discipline"
18
+ ([geneseed-context.js](plugins/geneseed-context.js) header;
19
+ `project_geneseed_enforcement` memory). A pure "law: read the docs folder"
20
+ approach regresses to instruction — the model reads *if* it obeys, *if* the law
21
+ names the right folder, and re-reads every session.
22
+
23
+ This spec keeps injection while removing the per-repo `context.json`: the **global
24
+ plugin discovers the current repo's docs by convention at session start** and
25
+ injects them. Per-project knowledge moves from a committed manifest into the
26
+ plugin's runtime glob. A fallback Law (§8) covers tools/repos the plugin can't.
27
+
28
+ Three tiers, and where this lands:
29
+
30
+ | Tier | Global? | Per-repo file? | Enforcement |
31
+ |---|---|---|---|
32
+ | Law only ("read docs/") | ✅ | none | ❌ soft |
33
+ | **Convention-glob plugin (this spec)** | ✅ | none (optional override) | ✅ injected |
34
+ | Per-repo `context.json` (today) | plugin global, manifest local | yes | ✅ injected, declarative |
35
+
36
+ ---
37
+
38
+ ## 1. Deployment model — everything global
39
+
40
+ Render the harness contents straight into OpenCode's global config dir. Nothing
41
+ is committed into a work repo.
42
+
43
+ | Piece | Global location | Loaded by |
44
+ |---|---|---|
45
+ | Entrypoint rules | `~/.config/opencode/AGENT.md` | `opencode.json` `instructions` (absolute path) |
46
+ | Laws | inlined in `AGENT.md` (already) | via above |
47
+ | Subagents | `~/.config/opencode/agents/*.md` | OpenCode global agents dir |
48
+ | Skills | `~/.config/opencode/skills/<name>/SKILL.md` | native `skill` tool (model-invoked) — see §9.1 |
49
+ | Plugins | `~/.config/opencode/plugins/*.js` | OpenCode auto-load |
50
+ | Memory store | `$GENESEED_HARNESS/memory` (or `$GENESEED_MEMORY`) | learn plugin |
51
+ | Project context | **auto-discovered per repo** by the context plugin | this spec |
52
+
53
+ `~/.config/opencode/opencode.json`:
54
+
55
+ ```json
56
+ {
57
+ "$schema": "https://opencode.ai/config.json",
58
+ "instructions": ["/home/<user>/.config/opencode/AGENT.md"]
59
+ }
60
+ ```
61
+
62
+ > Use an **absolute** path. A repo-relative `"AGENT.md"` in a *global* config
63
+ > would resolve against each repo's root and usually miss.
64
+
65
+ **Confirmed (OpenCode docs — config + plugins).** `~/.config/opencode/` loads
66
+ `agents/`, `commands/`, `plugins/`, and `skills/`. Notes that shape this spec:
67
+
68
+ - **Subdir names are plural** (`agents/`, `commands/`, `modes/`, `plugins/`,
69
+ `skills/`, `tools/`, `themes/`). Singular (`agent/`, `command/`) is *backwards-
70
+ compat only* — the current Geneseed build emits singular; the global emit (§9)
71
+ must write **plural**.
72
+ - **Native `skills/` dir exists** — OpenCode has first-class skills *separate* from
73
+ commands. Today the harness maps skills → commands; globally we may map them →
74
+ `skills/` instead (§12 open question).
75
+ - **`OPENCODE_CONFIG_DIR`** relocates the *entire* config dir (searched for
76
+ `agents/`, `commands/`, `modes/`, `plugins/` like `.opencode`). Use it to keep
77
+ the global harness in a **git-tracked** folder instead of `~/.config/opencode`.
78
+ - **Precedence:** global config < project config < `OPENCODE_CONFIG_DIR` <
79
+ inline/managed. A project `opencode.json` still overrides the global one.
80
+
81
+ ---
82
+
83
+ ## 2. Context plugin — responsibilities (every block)
84
+
85
+ The redesigned `geneseed-context.js` must cover all of the following. Blocks
86
+ marked **(new)** are added on top of today's behavior.
87
+
88
+ 1. **Resolve source** — pick override manifest *or* auto-discovery (§3.1).
89
+ 2. **Auto-discovery** **(new)** — glob the repo cwd by convention (§3.2).
90
+ 3. **Classify** — split candidates into `eager` / `lazy` (§3.2 table).
91
+ 4. **Budget & demote** **(new)** — enforce size caps; demote oversized eager → lazy (§3.3).
92
+ 5. **Override merge** **(new)** — `.harness` / `context.json` add, pin, or exclude (§3.4).
93
+ 6. **Build injection block** — header, eager bodies, lazy listing, idempotency marker (§3.5).
94
+ 7. **Idempotency** **(new)** — per-instance dedup *and* cross-instance transcript check (§4).
95
+ 8. **Event + session gating** — fire on `session.created`; skip `geneseed-*` sessions (§5).
96
+ 9. **Inject** — `session.prompt({ noReply: true })`.
97
+ 10. **Error handling** — swallow everything; never block a session (§6).
98
+ 11. **Logging** — one structured stderr line per outcome (§7).
99
+
100
+ ---
101
+
102
+ ## 3. Context discovery — the core
103
+
104
+ ### 3.1 Resolution order (first match wins)
105
+
106
+ ```
107
+ 1. $GENESEED_CONTEXT explicit manifest path -> declarative mode
108
+ 2. ./.harness/context.json per-repo override -> declarative mode
109
+ 3. ./context.json legacy per-repo manifest -> declarative mode
110
+ 4. (none of the above) -> AUTO-DISCOVERY (convention glob)
111
+ ```
112
+
113
+ - **Declarative mode** = today's behavior, extended to accept glob `path`s and an
114
+ `exclude` array (§3.4). Back-compatible: an existing flat `context.json` still works.
115
+ - **Auto-discovery** = the new default. Zero per-repo files.
116
+
117
+ Discovery always runs against the **repo root** = the session's `directory` /
118
+ `worktree` (walk up from cwd to the git root; fall back to cwd).
119
+
120
+ ### 3.2 Auto-discovery convention
121
+
122
+ Scanned relative to the repo root. **Eager** = injected in full. **Lazy** = only
123
+ *listed* (path + first H1/description) so the agent knows it exists and reads on demand.
124
+
125
+ | Class | Patterns (root-relative) | Rationale |
126
+ |---|---|---|
127
+ | **eager** | `AGENTS.md`, `AGENT.md`, `CLAUDE.md`, `.cursorrules`, `.harness/*.md` | agent-directed rules, small, always relevant |
128
+ | **eager** | `README.md` (root only), `CONTRIBUTING.md` (root only) | canonical entry doc |
129
+ | **lazy** | `docs/**/*.md`, `doc/**/*.md`, `documentation/**/*.md` | doc trees — large, occasional |
130
+ | **lazy** | `**/ADR/**/*.md`, `**/adr/**/*.md`, `architecture/**/*.md` | decision records |
131
+ | **lazy** | root `*.md` other than the eager ones (e.g. `CHANGELOG.md`) | misc root docs |
132
+ | **lazy** | `packages/*/README.md`, `apps/*/README.md` | monorepo package entry docs |
133
+ | **exclude (always)** | `node_modules/**`, `.git/**`, `dist/**`, `build/**`, `vendor/**`, `**/*.min.md` | never scan |
134
+
135
+ Rules:
136
+ - **Dedup against `instructions`.** If the repo's own `AGENTS.md`/`AGENT.md` is the
137
+ same file OpenCode already loads via `instructions`, skip it (avoid the
138
+ double-load class of bug). Compare resolved absolute paths.
139
+ - **Globs are dependency-free.** Implement a tiny matcher (`**`, `*`) in the
140
+ plugin — do not add an npm dep. Cap directory recursion depth (e.g. 6) so a
141
+ pathological tree can't hang discovery.
142
+ - **Determinism.** Sort matches lexicographically before injecting so the block is
143
+ stable across sessions (cache-friendly, diffable).
144
+
145
+ ### 3.3 Size & token budget
146
+
147
+ Injection happens every session — it must not blow the window.
148
+
149
+ | Cap | Default | Behavior on exceed |
150
+ |---|---|---|
151
+ | Per eager file | 16 KB | demote to **lazy** (list it, don't inject); log the demotion |
152
+ | Total eager budget | 48 KB | stop injecting eager bodies once hit; remaining eager → listed as lazy |
153
+ | Lazy listing | name + first H1 line only | never inject lazy bodies |
154
+ | Max files scanned | 2000 | stop walking; log truncation |
155
+
156
+ All caps overridable via env (`GENESEED_EAGER_FILE_KB`, `GENESEED_EAGER_TOTAL_KB`).
157
+ **No silent truncation** — every demotion/cap hit logs (Lex: no silent caps).
158
+
159
+ ### 3.4 Override / escape-hatch schema
160
+
161
+ `./.harness/context.json` (preferred) or `./context.json`. Same schema as today,
162
+ plus two additions. Any override file switches off auto-discovery unless it sets
163
+ `"extend": true`.
164
+
165
+ ```jsonc
166
+ {
167
+ // optional: keep auto-discovery AND apply these rules on top of it
168
+ "extend": true,
169
+ "context": [
170
+ { "path": "docs/architecture.md", "load": "eager", "description": "system overview" },
171
+ { "path": "docs/**/*.md", "load": "lazy" }, // globs allowed
172
+ { "path": "internal/secrets.md", "load": "exclude" } // hard exclude
173
+ ]
174
+ }
175
+ ```
176
+
177
+ - `load`: `eager` | `lazy` | `exclude` (new).
178
+ - `path`: absolute, repo-relative, or a glob.
179
+ - `extend`: `false`/absent → manifest is the *complete* list (today's semantics).
180
+ `true` → auto-discovery runs first, then manifest entries add/override/exclude.
181
+ - Precedence within merge: explicit manifest entry > auto-discovered classification.
182
+
183
+ This is the `.harness` hatch the design calls for: drop one tiny file only when a
184
+ repo's layout defeats the convention.
185
+
186
+ ### 3.5 Injection block format (mirror `harness.py cmd_context`)
187
+
188
+ Byte-identical structure to [harness.py:237-263](../../rituals/harness.py) so both
189
+ enforcement paths read the same. Adds a machine marker (first line) for §4.
190
+
191
+ ```
192
+ <!-- geneseed-context:v2 -->
193
+ === PROJECT CONTEXT — binding for this repo per Law XVIII ===
194
+
195
+ ----- <path> — <description> -----
196
+ <full file contents, trailing newlines stripped>
197
+
198
+ ----- <path2> -----
199
+ <...>
200
+
201
+ --- Lazy entries (load only when the task needs them) ---
202
+ - docs/architecture/overview.md — RF pipeline
203
+ - CHANGELOG.md
204
+ - [demoted: README.md exceeded 16 KB — read on demand]
205
+ ```
206
+
207
+ - Header keeps the exact `=== PROJECT CONTEXT … Law XVIII ===` wording.
208
+ - A `MISSING` eager file emits `[context] MISSING eager file: <err>` inline (as today).
209
+ - The `<!-- geneseed-context:v2 -->` marker is the idempotency sentinel.
210
+
211
+ ---
212
+
213
+ ## 4. Idempotency & dedup (kills the double-injection)
214
+
215
+ Two layers:
216
+
217
+ 1. **Per-instance** — keep the `done` Set keyed by session id (today's guard).
218
+ Stops one plugin instance re-firing on a repeated `session.created`.
219
+ 2. **Cross-instance (new)** — before injecting, read the transcript
220
+ (`client.session.messages({ path: { id } })`) and skip if any message part
221
+ already contains `<!-- geneseed-context:v2 -->`. This catches a global + leftover
222
+ project copy both firing.
223
+
224
+ > **Docs-confirmed why this is needed:** OpenCode dedups plugins *by npm package
225
+ > name+version only* — "a local plugin and an npm plugin with similar names are
226
+ > both loaded separately," and global plugins load before project plugins. Two
227
+ > local `.js` copies (global `~/.config/opencode/plugins/` + project
228
+ > `.opencode/plugins/`) **always** both load. So the marker check is mandatory and
229
+ > single-install (§9–10) is the only hard guarantee.
230
+
231
+ **Honest limit:** if two instances fire *simultaneously* they can both read an
232
+ empty transcript and both inject (race). The transcript check shrinks the window
233
+ but does not close it. The real guarantee is **single global install** — §9 emits
234
+ exactly one copy and the setup guide (§10) removes project copies. Document this.
235
+
236
+ ---
237
+
238
+ ## 5. Events & session gating
239
+
240
+ - Fire only on `event.type === "session.created"`.
241
+ - Extract sid from `properties.sessionID | payload.sessionID | properties.info.id |
242
+ payload.info.id` (as today).
243
+ - **Skip throwaway sessions:** if `session.get(...).title` starts with `geneseed-`,
244
+ return (don't pollute the learn plugin's distil sessions).
245
+ - Inject via `client.session.prompt({ path: { id }, body: { noReply: true, parts: [{ type: "text", text: block }] } })`.
246
+
247
+ ---
248
+
249
+ ## 6. Error handling
250
+
251
+ - Every step wrapped; any failure → log to stderr, return, **never throw**. A
252
+ broken discovery must not block a session start (matches `cmd_context` exit-0
253
+ contract).
254
+ - Missing repo root → fall back to cwd. No docs found → inject nothing (silent
255
+ except one debug log).
256
+
257
+ ---
258
+
259
+ ## 7. Logging (stderr, one line per outcome)
260
+
261
+ ```
262
+ [geneseed-context] injected: 3 eager (41 KB), 12 lazy listed [repo=/path]
263
+ [geneseed-context] demoted README.md -> lazy (18 KB > 16 KB cap)
264
+ [geneseed-context] skipped: already injected (marker present)
265
+ [geneseed-context] skipped: geneseed-* session
266
+ [geneseed-context] no docs discovered in <repo>
267
+ [geneseed-context] error: <message>
268
+ ```
269
+
270
+ ---
271
+
272
+ ## 8. Fallback Law (for tools without the plugin)
273
+
274
+ Add to the universal laws so non-OpenCode tools and uncovered repos still get
275
+ project context — the *instruction* tier behind the *injection* tier:
276
+
277
+ > **Law (Project Context Discovery).** When project context has not already been
278
+ > injected, before substantive work read the repo's agent-directed rules and entry
279
+ > docs — `AGENTS.md`/`AGENT.md`/`CLAUDE.md`, root `README.md`, and any `.harness/`
280
+ > manifest — and treat `docs/`, `adr/`, and architecture notes as lazy: consult
281
+ > them when the task touches their area. Prefer an injected PROJECT CONTEXT block
282
+ > when present; this Law is the fallback, not the primary path.
283
+
284
+ This is the "rely on the rule" path — kept as a safety net, not the main mechanism.
285
+
286
+ ---
287
+
288
+ ## 9. Build / emit changes
289
+
290
+ Add an emit target so the factory can render straight into the global dir.
291
+
292
+ `geneseed build --emit opencode-global [--theme NAME]` — **self-contained**: it
293
+ writes ONLY into `<cfg>` and builds **no sibling `Harness/`** (plural subdir names —
294
+ canonical):
295
+
296
+ 1. Render `AGENT.md` straight to `<cfg>/AGENT.md` (no Harness staging/copy).
297
+ 2. `agents/*.md` → `<cfg>/agents/*.md` (read-only agents keep `tools: { write:false, edit:false }`).
298
+ 3. skills → `<cfg>/skills/<name>/SKILL.md` (**native skills**, model-invoked — see §9.1).
299
+ 4. `plugins/*.js` → `<cfg>/plugins/*.js` (**single copy** — the fix).
300
+ 5. **Memory store** → `<cfg>/memory` (always classic English — never themed, like
301
+ `agents/`/`skills/`; a legacy themed `anamnesis/` is migrated into it): if it already has files,
302
+ left alone; else migrated once from a legacy `Harness/memory` (so a host moving
303
+ off a sibling bundle loses nothing), else seeded from the `src/memory` template.
304
+ The store is **not** owned-tracked — never deleted on re-emit. Point the learn
305
+ plugin at it with `GENESEED_HARNESS=<cfg>`.
306
+ 6. Write/merge `<cfg>/opencode.json` with the **absolute** `AGENT.md` path; never
307
+ clobbers a user-edited config — merges the `instructions` entry only.
308
+ 7. **No** `context.json` (auto-discovery is the default).
309
+ 8. `.geneseed-emit` marker written in `<cfg>` (build.py persists it regardless of
310
+ entrypoint), so a later bare `geneseed upgrade` keeps emitting globally.
311
+
312
+ ### 9.1 Skills → native `skills/` (decided)
313
+
314
+ Skills emit as **native OpenCode skills**, not slash commands:
315
+
316
+ - **Shape:** one directory per skill, `skills/<name>/SKILL.md` (not a flat
317
+ `commands/<name>.md`).
318
+ - **Frontmatter:** skill schema — `name`, `description` (+ optional `license`,
319
+ `metadata`). Drop the command-only `agent:` / `model:`
320
+ keys. Geneseed's `src/skills/*.md` frontmatter is transformed on emit.
321
+ - **Invocation:** model-invoked via the native `skill` tool with progressive
322
+ disclosure (the agent sees `description`s, loads the body on demand) — **not** a
323
+ user-typed `/name`. Each skill's `description` is therefore trigger-critical and
324
+ must be written to fire at the right moment.
325
+ - **Trade-off:** loses per-skill `agent:`/`model:` pinning that commands allowed
326
+ (the old `agent: build`); a skill runs in the current agent/model context. Audit
327
+ `src/skills/` for any that depended on it before emit.
328
+ - **Cross-adapter win:** `SKILL.md` is the *same artifact shape Claude Code uses*,
329
+ and OpenCode also auto-discovers `~/.claude/skills/*/SKILL.md` and
330
+ `~/.agents/skills/*/SKILL.md`. One skill source can feed both tools — collapsing
331
+ the two divergent emit paths and killing adapter drift. Optional: emit into
332
+ `~/.claude/skills/` for a single dir served to Claude Code *and* OpenCode.
333
+ - **Migration:** existing per-repo `.opencode/command/*.md` emits go stale; update
334
+ the adapter README, HOW-OPENCODE-LOADS, and `src/skills/_template.md`.
335
+
336
+ `<cfg>` resolution: `$OPENCODE_CONFIG_DIR` if set (lets the harness live in a
337
+ git-tracked folder), else `$XDG_CONFIG_HOME/opencode`, else `~/.config/opencode`.
338
+
339
+ `geneseed upgrade`: add `GENESEED_EMIT=opencode-global` to re-render globally on upgrade.
340
+
341
+ > **Windows config path: confirmed.** Modern OpenCode uses the same homedir-relative
342
+ > location on every OS, so `~/.config/opencode` resolves to `C:\Users\<user>\.config\opencode`
343
+ > on Windows — exactly what `_opencode_config_dir()` (`Path.home() / ".config" / "opencode"`)
344
+ > produces there. No `%APPDATA%` special case is needed (that was an old docs bug).
345
+ > `$OPENCODE_CONFIG_DIR` and `$XDG_CONFIG_HOME` still override, as on Unix.
346
+
347
+ ---
348
+
349
+ ## 10. How to set up (global, zero per-repo)
350
+
351
+ **One-time, on the machine that runs OpenCode.**
352
+
353
+ 1. **Emit globally** (from the Geneseed folder). No separate bundle build — this is
354
+ self-contained:
355
+ ```bash
356
+ cd /path/to/Geneseed
357
+ GENESEED_EMIT=opencode-global ./geneseed upgrade imperial # or any other theme
358
+ ```
359
+ This populates `~/.config/opencode/{AGENT.md,agents/,skills/,plugins/,memory/}`,
360
+ wires `opencode.json` to the absolute `AGENT.md`, and remembers the mode in
361
+ `<cfg>/.geneseed-emit` — so every later bare `geneseed upgrade` stays global.
362
+ (Direct equivalent: `geneseed build --emit opencode-global`.)
363
+
364
+ **Windows (PowerShell)** — same flow, no bash:
365
+ ```powershell
366
+ cd C:\path\to\Geneseed
367
+ $env:GENESEED_EMIT = "opencode-global"
368
+ .\geneseed.cmd upgrade main imperial # PowerShell runs a .cmd directly
369
+ ```
370
+ This populates `C:\Users\<user>\.config\opencode\{AGENT.md,agents,skills,plugins,memory}`.
371
+
372
+ 2. **Point the learn plugin at the in-config memory store** (once):
373
+ ```bash
374
+ export GENESEED_HARNESS="$HOME/.config/opencode" # so it writes <cfg>/memory
375
+ echo "export GENESEED_HARNESS=\"$HOME/.config/opencode\"" >> ~/.zshrc
376
+ ```
377
+ On **Windows (PowerShell)**:
378
+ ```powershell
379
+ setx GENESEED_HARNESS "$env:USERPROFILE\.config\opencode" # persists for new shells
380
+ ```
381
+ (Or `$OPENCODE_CONFIG_DIR` if you relocated the config dir.) The learn plugin also
382
+ auto-locates the in-config store, so this is only needed to pin it explicitly.
383
+
384
+ 3. **Remove every per-repo copy** (the source of the double-injection):
385
+ ```bash
386
+ # in each repo you previously ran --emit opencode in:
387
+ rm -rf .opencode/plugins .opencode/agents .opencode/agent .opencode/skills \
388
+ .opencode/command opencode.json context.json
389
+ # and confirm only ONE global plugin copy exists:
390
+ ls ~/.config/opencode/plugins/ # geneseed-context.js + geneseed-learn.js, once each
391
+ ```
392
+
393
+ 4. **Verify** (§11). A stray sibling `Harness/` from an older global build is now
394
+ unused — safe to delete once memory has migrated into `<cfg>/memory`.
395
+
396
+ **Per repo afterwards: nothing.** Open OpenCode in any repo — the global AGENT.md,
397
+ agents, and skills load, and the context plugin auto-discovers that repo's docs.
398
+ Only drop a `./.harness/context.json` (§3.4) in a repo whose layout defeats the
399
+ convention.
400
+
401
+ ---
402
+
403
+ ## 11. Acceptance checklist
404
+
405
+ - [x] Fresh repo with a `README.md` + `docs/` → exactly **one** PROJECT CONTEXT
406
+ block, README eager, `docs/**` listed lazy. *(verified — node fixture test)*
407
+ - [x] Repo with no docs → no block, one `no docs discovered` log, session starts clean.
408
+ - [x] Global + leftover project plugin copy → still **one** block (marker dedup). *(verified)*
409
+ - [x] >16 KB README → demoted to lazy, demotion logged, eager budget respected. *(verified)*
410
+ - [x] `.harness/context.json` with `extend:true` + `exclude` + pin → merged correctly. *(verified)*
411
+ - [x] `geneseed-*` distil session → no injection.
412
+ - [x] Plugin adds **no** npm dependency. *(stdlib `node:fs`/`node:path`/`node:url` only)*
413
+ - [x] Global re-emit removes stale owned files, preserves user files, writes no
414
+ `context.json`. *(verified — manifest cleanup test)*
415
+ - [ ] Malformed `.harness/context.json` → error logged, session still starts. *(swallowed by readJson; not explicitly tested)*
416
+ - [ ] Live OpenCode session on the work laptop (field-test caveat — event/SDK field names).
417
+
418
+ ---
419
+
420
+ ## 12. Non-goals / open questions
421
+
422
+ - **Not** removing the portable bundle or the per-repo `context.json` tier — both stay.
423
+ - **Race** on simultaneous dual-instance injection is mitigated, not eliminated
424
+ (§4) — single install is the guarantee (docs-confirmed: local plugins never dedup).
425
+ - **Resolved:** OpenCode global `agents/` + `commands/` + `skills/` loading is
426
+ confirmed (§1). Subdir names are plural (singular = back-compat).
427
+ - **Resolved:** Windows config-dir path is the same homedir-relative
428
+ `~/.config/opencode` (→ `C:\Users\<user>\.config\opencode`); no `%APPDATA%` case (§9).
429
+ - **Decided:** skills emit as **native `skills/<name>/SKILL.md`** (§9.1) — model-
430
+ invoked, progressive disclosure, same shape as Claude Code skills. Cost: no slash
431
+ trigger, no per-skill `agent:`/`model:` pinning.
432
+ - **Open:** whether eager auto-discovery of a repo's `AGENTS.md` should be dropped
433
+ entirely (since `instructions` may already load it) or kept with path-dedup —
434
+ spec currently keeps it with dedup.
@@ -0,0 +1,158 @@
1
+ # How OpenCode loads a project
2
+
3
+ A reference for what OpenCode reads at startup, how Geneseed plugs into each
4
+ mechanism, and why a file can appear **listed twice**. Field names and event lists
5
+ are confirmed against the current OpenCode plugin + SDK docs; they can still shift
6
+ between versions, and the plugins degrade quietly if one does.
7
+
8
+ ## 1. Config discovery & merge
9
+
10
+ OpenCode does not read a single config — it **merges several**:
11
+
12
+ - **Global:** `~/.config/opencode/opencode.json` (on Windows, the same homedir-relative
13
+ path: `C:\Users\<user>\.config\opencode\opencode.json`).
14
+ - **Project:** `./opencode.json` or `./.opencode/opencode.json`, found by walking up
15
+ from the current directory to the worktree root.
16
+ - Project config **overrides** global on direct conflicts.
17
+
18
+ It also auto-loads an **`AGENTS.md`** at the project root with no config at all.
19
+
20
+ Because these sources merge rather than replace, **anything referenced in two of
21
+ them loads from each** — which is exactly why a file can show up twice (see §7).
22
+
23
+ ## 2. `instructions` — the rule/context files
24
+
25
+ The `instructions` array names files loaded into **every session** as ambient
26
+ rules. It accepts:
27
+
28
+ - absolute paths,
29
+ - repo-relative paths,
30
+ - globs (`"laws/*.md"`),
31
+ - URLs.
32
+
33
+ Geneseed points it at the bundle's **`AGENT.md`** (which inlines the laws). That is
34
+ all you need there — the rest of the harness is loaded by the plugins below.
35
+
36
+ ## 3. Plugins — event-driven JS/TS
37
+
38
+ Plugins are **auto-loaded** from a plugins directory at startup. **No entry in
39
+ `opencode.json` is required** (the `"plugin"` array is only for *npm-package*
40
+ plugins). Local plugin directories:
41
+
42
+ - **Global:** `~/.config/opencode/plugins/`
43
+ - **Project:** `.opencode/plugins/`
44
+
45
+ The folder is **`plugins`** (plural), both `.js` and `.ts` are accepted, and it does
46
+ **not** exist by default — create it the first time.
47
+
48
+ A plugin is an async function that receives a context object and returns hook
49
+ implementations:
50
+
51
+ ```js
52
+ export const MyPlugin = async ({ client, $, directory, worktree }) => ({
53
+ event: async ({ event }) => {
54
+ if (event.type === "session.idle") { /* … */ }
55
+ },
56
+ })
57
+ ```
58
+
59
+ - **`event({ event })`** — the catch-all; filter on `event.type`. Session events
60
+ include `session.created`, `session.idle`, `session.updated`, `session.compacted`,
61
+ `session.error`, plus `message.updated`, `tool.execute.before/after`, and more.
62
+ - **`client`** — the OpenCode SDK. Read a session's transcript with
63
+ `client.session.messages({ path: { id } })` → `{ info, parts }[]`; inject context
64
+ **without** triggering a reply with `client.session.prompt({ path, body: { noReply: true, parts } })`.
65
+ - **`$`** — a shell executor for running commands.
66
+
67
+ ## 4. Subagents, skills & commands
68
+
69
+ Subdir names are **plural** canonically (`agents/`, `skills/`, `commands/`,
70
+ `plugins/`, …); singular (`agent/`, `command/`) is back-compat only.
71
+
72
+ - `.opencode/agents/<name>.md` → a **subagent** (frontmatter: `description`,
73
+ `mode: subagent`, optional `permission:` to deny edit/bash/webfetch — Geneseed uses
74
+ this to make read-only agents truly read-only, shell included).
75
+ - `.opencode/skills/<name>/SKILL.md` → a **native skill** (frontmatter: `name`,
76
+ `description`) — model-invoked via the `skill` tool, progressive disclosure.
77
+ - `.opencode/commands/<name>.md` → a **slash command** (user-invoked `/name`).
78
+
79
+ Geneseed generates subagents and native skills from `src/` via `geneseed build
80
+ --emit opencode` (or globally with `--emit opencode-global`) — zero drift. It maps skills
81
+ to native **skills**, not slash commands (same `SKILL.md` shape as Claude Code).
82
+
83
+ ## 5. How Geneseed maps onto OpenCode
84
+
85
+ | OpenCode mechanism | Geneseed piece |
86
+ | --- | --- |
87
+ | `instructions` → `AGENT.md` | the rules, loaded every session |
88
+ | `.opencode/agents/`, `.opencode/skills/` | capability agents and native skills |
89
+ | plugin on `session.created` | **context plugin (v2)** — auto-discovers & injects the repo's `eager` docs |
90
+ | plugin on `experimental.session.compacting` | **context plugin** — re-pushes the `eager` docs so they survive compaction |
91
+ | plugin on `session.idle` | **learn plugin** — distils memory into `memory/` (debounced to fire once, at session end) |
92
+ | plugin on `tool.execute.before` | **guard plugin** — blocks secret-file writes and catastrophic shell (Laws I & IV; `GENESEED_GUARD=off\|warn`) |
93
+ | plugin registering a custom tool | **workflow plugin** — the `workflow` tool runs saved orchestration scripts from `workflows/` |
94
+ | `context.json` / `.harness/` (manifest) | *optional* override when discovery doesn't fit |
95
+
96
+ ## 6. LSP — diagnostics, not a tool
97
+
98
+ Geneseed sets `"lsp": true`, so OpenCode auto-starts a language server matching
99
+ each file's extension **when the file is opened**, and feeds its diagnostics back
100
+ to the model as ambient context.
101
+
102
+ The thing to know: **the LSP is not a tool the model can call.** There is no
103
+ "use the LSP" action — the model's toolset is `bash`/`read`/`write`/`edit`/`grep`/
104
+ `glob`/`task`/`webfetch` and nothing else. Diagnostics arrive as injected feedback
105
+ when a file is opened or edited; the model cannot summon them on demand. So a model
106
+ that says *"I have no LSP tool"* is **correct**, not broken — asking it to "trigger
107
+ the React LSP" can't be honored as a tool call.
108
+
109
+ OpenCode's own docs steer you the same way: language servers drift and eat memory,
110
+ so *"it is often better to have the agent run lint, typecheck, or other diagnostic
111
+ CLI tools directly."* A clean `eslint` (and `tsc --noEmit` where there's a TS
112
+ project) is the **same signal** the LSP would inject — just fetched on purpose
113
+ instead of ambiently. That is exactly what a model running `npx eslint <file>` is
114
+ doing, and it's the recommended path.
115
+
116
+ **JS/JSX caveat (e.g. `web/`):** the bundled TypeScript server attaches to `.jsx`
117
+ by extension even with no config, but only in loose single-file mode. A minimal
118
+ `web/jsconfig.json` (no `checkJs`) scopes the directory as a project so the server
119
+ resolves imports and JSX properly — present in this repo for that reason. Real-bug
120
+ detection still lives in `eslint.config.js`; `jsconfig.json` only makes the LSP
121
+ attach as a project, it does not turn on type-checking.
122
+
123
+ ## 7. "Why is `context.json` (or `AGENT.md`) listed twice?"
124
+
125
+ Because OpenCode **merges every `opencode.json` it finds** — global, project, and
126
+ any discovered while walking up the tree. If the same file is named in two
127
+ `instructions` arrays, it is loaded once **per source**. This is harmless (just
128
+ duplicated context), but to clean it up, name each file in **one** config only.
129
+
130
+ Geneseed's emit lists **only `AGENT.md`** in `instructions` (never `context.json` —
131
+ the context plugin handles project docs by auto-discovery), so the classic
132
+ "manifest listed twice" no longer happens. Keep:
133
+
134
+ ```json
135
+ { "instructions": ["/abs/path/to/AGENT.md"] }
136
+ ```
137
+
138
+ If you still see `AGENT.md` loaded twice, it is named in two merged `opencode.json`
139
+ files — find and de-dup:
140
+
141
+ ```bash
142
+ for f in ~/.config/opencode/opencode.json ./opencode.json ./.opencode/opencode.json; do
143
+ echo "== $f =="; cat "$f" 2>/dev/null; echo
144
+ done
145
+ ```
146
+
147
+ ### The PROJECT CONTEXT block twice
148
+
149
+ The modern cause of a *doubled injection* is **two copies of the context plugin**
150
+ (global `~/.config/opencode/plugins/` + a leftover project `.opencode/plugins/`) —
151
+ OpenCode dedups plugins by npm name+version only, so two local `.js` files both
152
+ load. The v2 plugin guards against this with a transcript marker
153
+ (`<!-- geneseed-context:v2 -->`) — it skips a session that already carries it — but
154
+ the clean fix is a single install. Remove the stray project copy:
155
+
156
+ ```bash
157
+ rm -rf .opencode/plugins .opencode/agents .opencode/skills .opencode/command .opencode/agent
158
+ ```