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.
- package/CHANGELOG.md +938 -0
- package/DESIGN.md +1423 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +48 -0
- package/README.md +336 -0
- package/SETUP.md +1027 -0
- package/SHIPPED.md +70 -0
- package/adapters/bob/README.md +100 -0
- package/adapters/claude-code/README.md +101 -0
- package/adapters/claude-code/settings.json +47 -0
- package/adapters/claude-code/skills/geneseed/SKILL.md +72 -0
- package/adapters/copilot/README.md +76 -0
- package/adapters/opencode/GLOBAL-HARNESS-SPEC.md +434 -0
- package/adapters/opencode/HOW-OPENCODE-LOADS.md +158 -0
- package/adapters/opencode/README.md +582 -0
- package/adapters/opencode/agents/orchestrator.md +25 -0
- package/adapters/opencode/opencode.json +44 -0
- package/adapters/opencode/plugins/geneseed-activity.js +430 -0
- package/adapters/opencode/plugins/geneseed-context.js +876 -0
- package/adapters/opencode/plugins/geneseed-guard.js +290 -0
- package/adapters/opencode/plugins/geneseed-learn.js +396 -0
- package/adapters/opencode/plugins/geneseed-notify.js +142 -0
- package/adapters/opencode/plugins/geneseed-ponytail.js +148 -0
- package/adapters/opencode/plugins/geneseed-workflow.js +183 -0
- package/adapters/opencode/workflows/_runtime.js +277 -0
- package/adapters/opencode/workflows/council.js +64 -0
- package/adapters/opencode/workflows/dispatch.js +89 -0
- package/adapters/opencode/workflows/research-plan-implement.js +43 -0
- package/adapters/opencode/workflows/review.js +57 -0
- package/bin/geneseed-cli.mjs +412 -0
- package/bin/geneseed-hook.mjs +129 -0
- package/bin/geneseed.mjs +1086 -0
- package/docs/declined.md +149 -0
- package/docs/limits.md +270 -0
- package/docs/opencode-plugin-setup.md +64 -0
- package/docs/token-footprint.md +68 -0
- package/docs/web/_groups.json +45 -0
- package/docs/web/about.md +6 -0
- package/docs/web/adapters-claude-code.md +8 -0
- package/docs/web/adapters-opencode-loads.md +8 -0
- package/docs/web/adapters-opencode-spec.md +8 -0
- package/docs/web/adapters-opencode.md +8 -0
- package/docs/web/agents.md +8 -0
- package/docs/web/authoring.md +11 -0
- package/docs/web/autostart.md +9 -0
- package/docs/web/claude-hooks.md +36 -0
- package/docs/web/cli.md +6 -0
- package/docs/web/collaboration.md +27 -0
- package/docs/web/configure-wiki.md +9 -0
- package/docs/web/design.md +7 -0
- package/docs/web/env-knobs.md +9 -0
- package/docs/web/exclusions.md +26 -0
- package/docs/web/first-session.md +28 -0
- package/docs/web/footprint.md +31 -0
- package/docs/web/foreman-mode.md +33 -0
- package/docs/web/glossary.md +6 -0
- package/docs/web/harnesses.md +28 -0
- package/docs/web/headless.md +9 -0
- package/docs/web/ingest-docs.md +9 -0
- package/docs/web/install-paths.md +9 -0
- package/docs/web/install-quick.md +35 -0
- package/docs/web/lsp-overview.md +37 -0
- package/docs/web/mcp-claude-code.md +10 -0
- package/docs/web/mcp-filesystem.md +9 -0
- package/docs/web/mcp-gitlab.md +9 -0
- package/docs/web/mcp-markitdown.md +9 -0
- package/docs/web/mcp-overview.md +34 -0
- package/docs/web/mcp-trouble.md +9 -0
- package/docs/web/mcp-verify.md +9 -0
- package/docs/web/memory.md +7 -0
- package/docs/web/migrate.md +39 -0
- package/docs/web/model.md +20 -0
- package/docs/web/notebook.md +7 -0
- package/docs/web/pipelines.md +24 -0
- package/docs/web/plugin-activity.md +23 -0
- package/docs/web/plugin-context.md +26 -0
- package/docs/web/plugin-guard.md +24 -0
- package/docs/web/plugin-learn.md +27 -0
- package/docs/web/plugin-notify.md +24 -0
- package/docs/web/plugin-ponytail.md +23 -0
- package/docs/web/plugin-setup.md +7 -0
- package/docs/web/plugin-workflow.md +24 -0
- package/docs/web/plugins.md +17 -0
- package/docs/web/project-context.md +9 -0
- package/docs/web/rules.md +8 -0
- package/docs/web/run-anywhere.md +9 -0
- package/docs/web/self-improve.md +8 -0
- package/docs/web/setup-choices.md +39 -0
- package/docs/web/skills.md +8 -0
- package/docs/web/themes-author.md +8 -0
- package/docs/web/themes.md +9 -0
- package/docs/web/token-footprint.md +7 -0
- package/docs/web/trouble.md +38 -0
- package/docs/web/upgrade.md +9 -0
- package/docs/web/verify.md +30 -0
- package/docs/web/wiki.md +7 -0
- package/docs/web/worktree.md +10 -0
- package/docs/web-ui.md +144 -0
- package/docs/wiki.md +43 -0
- package/geneseed +39 -0
- package/geneseed.cmd +34 -0
- package/harness.config.json +6 -0
- package/js/anim.mjs +326 -0
- package/js/catalog.mjs +112 -0
- package/js/checkout.mjs +88 -0
- package/js/cli-table.json +1034 -0
- package/js/cli.mjs +498 -0
- package/js/diff.mjs +384 -0
- package/js/doctor.mjs +1364 -0
- package/js/emit.mjs +1373 -0
- package/js/excludes.mjs +271 -0
- package/js/generate.mjs +379 -0
- package/js/hooks.mjs +1026 -0
- package/js/hosts.mjs +253 -0
- package/js/installs.mjs +378 -0
- package/js/inventory.mjs +175 -0
- package/js/lib/fs.mjs +913 -0
- package/js/lib/proc.mjs +28 -0
- package/js/lib/udiff.mjs +275 -0
- package/js/link.mjs +286 -0
- package/js/mcp.mjs +335 -0
- package/js/memory.mjs +108 -0
- package/js/menu.mjs +118 -0
- package/js/migrate.mjs +251 -0
- package/js/native.mjs +426 -0
- package/js/opencode.mjs +325 -0
- package/js/registry.mjs +110 -0
- package/js/render.mjs +282 -0
- package/js/settings.mjs +924 -0
- package/js/setup.mjs +492 -0
- package/js/status.mjs +281 -0
- package/js/themes.mjs +195 -0
- package/js/tui.mjs +444 -0
- package/js/uninstall.mjs +1137 -0
- package/js/update.mjs +910 -0
- package/js/web/actions.mjs +868 -0
- package/js/web/activity.mjs +284 -0
- package/js/web/api.mjs +873 -0
- package/js/web/docs.mjs +531 -0
- package/js/web/graph.mjs +0 -0
- package/js/web/jobs.mjs +480 -0
- package/js/web/server.mjs +1135 -0
- package/package.json +54 -0
- package/registry.json +474 -0
- package/src/AGENT.md.tmpl +390 -0
- package/src/agents/_template.md +76 -0
- package/src/agents/advocate.md +36 -0
- package/src/agents/architect.md +55 -0
- package/src/agents/developer.md +66 -0
- package/src/agents/docs.md +54 -0
- package/src/agents/empiricist.md +39 -0
- package/src/agents/explorer.md +54 -0
- package/src/agents/framer.md +36 -0
- package/src/agents/historian.md +51 -0
- package/src/agents/operator.md +37 -0
- package/src/agents/pragmatist.md +37 -0
- package/src/agents/reviewer.md +52 -0
- package/src/agents/security.md +57 -0
- package/src/agents/skeptic.md +48 -0
- package/src/agents/steward.md +36 -0
- package/src/agents/tester.md +54 -0
- package/src/agents/user-advocate.md +36 -0
- package/src/agents/visionary.md +36 -0
- package/src/laws/universal.md +387 -0
- package/src/memory/README.md +109 -0
- package/src/memory/gitignore +6 -0
- package/src/modes/README.md +26 -0
- package/src/modes/direct.md +2 -0
- package/src/modes/foreman.md +19 -0
- package/src/notebook/README.md +39 -0
- package/src/notebook/gitignore +7 -0
- package/src/postures/README.md +31 -0
- package/src/postures/artisan.md +14 -0
- package/src/postures/assistant.md +12 -0
- package/src/postures/expert.md +11 -0
- package/src/postures/mentor.md +11 -0
- package/src/postures/peer.md +12 -0
- package/src/skills/_template.md +47 -0
- package/src/skills/brainstorm.md +28 -0
- package/src/skills/clarify.md +28 -0
- package/src/skills/codebase-design.md +44 -0
- package/src/skills/commit.md +48 -0
- package/src/skills/council.md +34 -0
- package/src/skills/crash-course.md +28 -0
- package/src/skills/daydream/.claude-plugin/plugin.json +9 -0
- package/src/skills/daydream/SKILL.md +74 -0
- package/src/skills/daydream/VENDOR.md +25 -0
- package/src/skills/daydream/critic-prompt.md +38 -0
- package/src/skills/daydream/instructions.md +422 -0
- package/src/skills/daydream/synthesizer-prompt.md +41 -0
- package/src/skills/debug.md +37 -0
- package/src/skills/decode.md +28 -0
- package/src/skills/develop.md +29 -0
- package/src/skills/document-project.md +79 -0
- package/src/skills/domain-modeling.md +38 -0
- package/src/skills/drill.md +28 -0
- package/src/skills/feynman.md +26 -0
- package/src/skills/forge-mcp.md +48 -0
- package/src/skills/fresh-eyes.md +29 -0
- package/src/skills/frontend-design.md +58 -0
- package/src/skills/gap-detector.md +27 -0
- package/src/skills/geneseed-code-review.md +33 -0
- package/src/skills/geneseed.md +29 -0
- package/src/skills/git-archaeology.md +47 -0
- package/src/skills/git-rescue.md +68 -0
- package/src/skills/handoff.md +29 -0
- package/src/skills/herdr.md +164 -0
- package/src/skills/ingest.md +49 -0
- package/src/skills/learning-path.md +26 -0
- package/src/skills/migrate.md +45 -0
- package/src/skills/opencode-theme.md +52 -0
- package/src/skills/parallel-agents.md +28 -0
- package/src/skills/pipeline.md +52 -0
- package/src/skills/plan.md +45 -0
- package/src/skills/ponytail.md +29 -0
- package/src/skills/profile.md +58 -0
- package/src/skills/prose.md +42 -0
- package/src/skills/prototype.md +44 -0
- package/src/skills/react-view-transitions/AGENTS.md +955 -0
- package/src/skills/react-view-transitions/README.md +42 -0
- package/src/skills/react-view-transitions/SKILL.md +320 -0
- package/src/skills/react-view-transitions/VENDOR.md +16 -0
- package/src/skills/react-view-transitions/metadata.json +12 -0
- package/src/skills/react-view-transitions/references/css-recipes.md +242 -0
- package/src/skills/react-view-transitions/references/implementation.md +182 -0
- package/src/skills/react-view-transitions/references/nextjs.md +176 -0
- package/src/skills/react-view-transitions/references/patterns.md +262 -0
- package/src/skills/refactor.md +32 -0
- package/src/skills/release.md +43 -0
- package/src/skills/repo-map.md +36 -0
- package/src/skills/research.md +42 -0
- package/src/skills/review-response.md +36 -0
- package/src/skills/roast-me.md +28 -0
- package/src/skills/rule.md +100 -0
- package/src/skills/ship.md +49 -0
- package/src/skills/tdd.md +31 -0
- package/src/skills/tickets.md +44 -0
- package/src/skills/token-report/SKILL.md +76 -0
- package/src/skills/token-report/VENDOR.md +23 -0
- package/src/skills/token-report/scripts/token_report.mjs +1301 -0
- package/src/skills/wayfinder.md +49 -0
- package/src/skills/wiki.md +68 -0
- package/src/skills/workflow.md +38 -0
- package/themes/README.md +69 -0
- package/themes/_TEMPLATE.json +147 -0
- package/themes/biker.json +147 -0
- package/themes/commentator.json +147 -0
- package/themes/cyberpunk.json +147 -0
- package/themes/gamer.json +147 -0
- package/themes/imperial.json +147 -0
- package/themes/joker.json +147 -0
- package/themes/marvin.json +147 -0
- package/themes/mean.json +147 -0
- package/themes/military.json +147 -0
- package/themes/neutral.json +147 -0
- package/themes/opencode/README.md +58 -0
- package/themes/opencode/catppuccin.json +27 -0
- package/themes/opencode/dracula.json +27 -0
- package/themes/opencode/everforest.json +27 -0
- package/themes/opencode/gruvbox.json +27 -0
- package/themes/opencode/kanagawa.json +27 -0
- package/themes/opencode/neon.json +27 -0
- package/themes/opencode/nord.json +27 -0
- package/themes/opencode/rosepine.json +27 -0
- package/themes/opencode/tokyonight.json +27 -0
- package/themes/pirate.json +147 -0
- package/themes/sports.json +147 -0
- package/themes/verstappen.json +147 -0
- package/themes/wizard.json +147 -0
- package/web/dist/assets/About-DX1-VTBP.js +1 -0
- package/web/dist/assets/Activity-Dp9NaXOn.js +1 -0
- package/web/dist/assets/ActivityDetail-HpOBtrXS.js +1 -0
- package/web/dist/assets/Diff-Ct4G3Se8.js +5 -0
- package/web/dist/assets/Doctor-DGjkZFuA.js +1 -0
- package/web/dist/assets/Graph-b8o-S6kv.js +1 -0
- package/web/dist/assets/Harnesses-gr3-aHBF.js +1 -0
- package/web/dist/assets/Laws-DTwF5tTC.js +1 -0
- package/web/dist/assets/Library-BEZscyaQ.js +1 -0
- package/web/dist/assets/Markdown-k_LSLBGq.js +1 -0
- package/web/dist/assets/Profile-DydukTxP.js +1 -0
- package/web/dist/assets/Rules-CIRG4Ldt.js +1 -0
- package/web/dist/assets/Skills-Buoi1IBr.js +1 -0
- package/web/dist/assets/StatusBadge-CE_AJttl.js +1 -0
- package/web/dist/assets/Themes-CI4o3gJC.js +2 -0
- package/web/dist/assets/activity-BCW7e6Cy.js +1 -0
- package/web/dist/assets/audiowide-latin-400-normal-6GFCX7ni.woff2 +0 -0
- package/web/dist/assets/geist-mono-latin-400-normal-DKaoCDn5.woff2 +0 -0
- package/web/dist/assets/geist-mono-latin-500-normal-C3sF8Y1B.woff2 +0 -0
- package/web/dist/assets/geist-mono-latin-600-normal-BHzjB6_C.woff2 +0 -0
- package/web/dist/assets/hanken-grotesk-latin-400-italic-Bserb8X5.woff2 +0 -0
- package/web/dist/assets/hanken-grotesk-latin-400-normal-BG6hkEXj.woff2 +0 -0
- package/web/dist/assets/hanken-grotesk-latin-500-italic-BGfwwhek.woff2 +0 -0
- package/web/dist/assets/hanken-grotesk-latin-500-normal-DrDcrrxK.woff2 +0 -0
- package/web/dist/assets/hanken-grotesk-latin-600-normal-CIXX6EOa.woff2 +0 -0
- package/web/dist/assets/hanken-grotesk-latin-700-normal-CeQ8H3UY.woff2 +0 -0
- package/web/dist/assets/ibm-plex-mono-latin-400-normal-DMJ8VG8y.woff2 +0 -0
- package/web/dist/assets/ibm-plex-mono-latin-500-normal-DSY6xOcd.woff2 +0 -0
- package/web/dist/assets/ibm-plex-mono-latin-600-normal-BgSNZQsw.woff2 +0 -0
- package/web/dist/assets/ibm-plex-serif-latin-400-normal-BIGslYFI.woff2 +0 -0
- package/web/dist/assets/ibm-plex-serif-latin-500-normal-REKAfBVG.woff2 +0 -0
- package/web/dist/assets/ibm-plex-serif-latin-600-normal-DAxitmSu.woff2 +0 -0
- package/web/dist/assets/index-B1PIx7RM.js +1 -0
- package/web/dist/assets/index-BnTQUSUz.js +12 -0
- package/web/dist/assets/index-Ck2iCdaC.js +2 -0
- package/web/dist/assets/index-DUCsDv7z.css +1 -0
- package/web/dist/assets/inter-latin-400-normal-C38fXH4l.woff2 +0 -0
- package/web/dist/assets/inter-latin-500-normal-Cerq10X2.woff2 +0 -0
- package/web/dist/assets/inter-latin-600-normal-LgqL8muc.woff2 +0 -0
- package/web/dist/assets/inter-latin-700-normal-Yt3aPRUw.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-500-normal-BWZEU5yA.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-600-normal-C8RAYTDA.woff2 +0 -0
- package/web/dist/assets/marked.esm-JKvyS0Pp.js +46 -0
- package/web/dist/assets/oswald-latin-400-normal-BAFo8sP8.woff2 +0 -0
- package/web/dist/assets/oswald-latin-500-normal-B-eyT0Dw.woff2 +0 -0
- package/web/dist/assets/oswald-latin-600-normal-plFmSr5g.woff2 +0 -0
- package/web/dist/assets/oswald-latin-700-normal-vy6hmKSr.woff2 +0 -0
- package/web/dist/assets/poppins-latin-400-normal-cpxAROuN.woff2 +0 -0
- package/web/dist/assets/poppins-latin-500-normal-C8OXljZJ.woff2 +0 -0
- package/web/dist/assets/poppins-latin-600-normal-zEkxB9Mr.woff2 +0 -0
- package/web/dist/assets/poppins-latin-700-normal-Qrb0O0WB.woff2 +0 -0
- package/web/dist/assets/react-DOpiTn5v.js +32 -0
- package/web/dist/assets/roman-DkYN0LX9.js +1 -0
- package/web/dist/assets/space-grotesk-latin-400-normal-CJ-V5oYT.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-500-normal-lFbtlQH6.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-600-normal-DjKNqYRj.woff2 +0 -0
- package/web/dist/assets/space-grotesk-latin-700-normal-RjhwGPKo.woff2 +0 -0
- package/web/dist/assets/space-mono-latin-400-italic-YylcN9Ay.woff2 +0 -0
- package/web/dist/assets/space-mono-latin-400-normal-Rg4St2Dn.woff2 +0 -0
- package/web/dist/assets/space-mono-latin-700-italic-vNvENeTh.woff2 +0 -0
- package/web/dist/assets/space-mono-latin-700-normal-mWgeinG7.woff2 +0 -0
- package/web/dist/icon-maskable.svg +10 -0
- package/web/dist/icon.svg +8 -0
- package/web/dist/index.html +21 -0
- package/web/dist/manifest.webmanifest +14 -0
- package/web/dist/sw.js +40 -0
- 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
|
+
```
|