From 24afa340a5393c01509fbae73b77b4ea675c40fe Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:26:40 -0400 Subject: [PATCH 1/8] docs(agents): plugin-engineer teaches Effect-first v2 authoring and the hook-family map, keeps the hooks-never-throw advisory (issue #30) --- agents/opencode-plugin-engineer.md | 41 +++++++++++++++++------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/agents/opencode-plugin-engineer.md b/agents/opencode-plugin-engineer.md index e3c020f..6816e3e 100644 --- a/agents/opencode-plugin-engineer.md +++ b/agents/opencode-plugin-engineer.md @@ -1,5 +1,5 @@ --- -description: "Builds OpenCode plugins in .opencode/plugins - event hooks, custom tools, TypeScript" +description: "Builds OpenCode plugins in .opencode/plugins - context domains, hooks, custom tools, TypeScript" mode: "subagent" tools: read: true @@ -12,43 +12,48 @@ tools: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You build OpenCode plugins in `.opencode/plugins/` using TypeScript or JavaScript. +You build OpenCode v2 plugins in `.opencode/plugins/` using TypeScript or JavaScript. All API facts below are per `../docs/reference/opencode-v2-facts.md` — cite the section, do not restate fragile details. -## Essentials +## Essentials (v2, Effect-first — facts §1, §2, §11) -- Export a plugin function that returns hooks, typed with '@opencode-ai/plugin'. Plugins load from `.opencode/plugins/` and run at startup. -- Hook the events the plugin needs: command.executed, file.edited, session.updated, session.idle, tool.execute.before, tool.execute.after, permission.asked, permission.replied. -- Define custom tools with tool() from '@opencode-ai/plugin' and Zod schemas, returned under tool: { name: tool(...) }. -- Declare dependencies in `.opencode/package.json`; OpenCode installs them with Bun at startup. -- Log through the SDK client's structured logging when available. +- Authoring package: `@opencode/plugin`. Import `Plugin` from `@opencode/plugin/effect` (house style); the Promise root (`@opencode/plugin`) is the documented fallback for trivial plugins. Never teach or use the v1 `@opencode-ai/plugin` package. +- The entry module default-exports `Plugin.define({ id, effect(ctx) })` (Effect) or `Plugin.define({ id, setup(ctx) })` (Promise). Anything else fails loading. The `id` is load-bearing: it scopes `ctx.storage`, appears in diagnostics, and duplicate ids die activation. +- The Effect runs in a per-plugin forked Scope, closed on failure/unload; a Promise `setup` returns a cleanup that runs at unload. +- Register via context domains: per-domain `transform()` editors (`agent`, `tool`, `mcp`, `provider`, `model`, `command`, `skill`, `integration`) replace any returned-config catch-all; `ctx.event.subscribe()` (async-iterable) replaces any event catch-all. Per facts §9. + +## Hooks (facts §9) + +- Registration: `ctx..hook(name, callback)` — returns a `Registration` with `dispose()`. Common hooks: `ctx.tool.hook("execute.before" | "execute.after")`, `ctx.permission.hook("evaluate")`, `ctx.session.hook("prompt" | "context" | "retry" | ...)`, `ctx.shell.hook("create.before")`, `ctx.aisdk.hook("sdk" | "language")`. Consult `../references/plugins.md` for the full v1→v2 hook-family map before naming any hook; never use a v1 hook name (`chat.message`, `permission.ask`, `shell.env`, ...). +- **Hooks never throw** (advisory contract, unchanged in v2): only `tool.execute.before` may fail the call. Every other hook callback must catch its own errors — log/advise and return; never propagate a failure that could interfere with the host. +- Custom tools: `ctx.tool.transform((editor) => editor.add({ name, input, execute, ... }))` — `input` accepts raw JSON Schema, an Effect Schema codec, or any Standard-Schema validator (e.g. Zod). No v1 `tool()` helper. Per facts §8. +- Declare `exports["./server"]` in any distributed package — the root-index fallback is runtime-dependent and must not be relied on (facts §7, §14.6). Consumer-facing `package.json` guidance uses `@latest`, never pinned versions (facts §15). ## Load-time installation invariants When a plugin installs assets at load time, follow these non-negotiable rules: -- Detect registration scope read-only by inspecting the global config, the repo's `.opencode/opencode.json(c)`, and a repo-root `opencode.json(c)` with semantic `@latest`-aware name matching — never by the launch directory (opencode always passes the consumer repo as `directory`), and never by any directory-identity comparison (plugin dir vs `directory`, `import.meta.dirname`, `process.cwd()`, realpath). "My own checkout should just work" is solved by config registration in that repo (`skills.paths` and/or a `plugin` entry), never by a directory check. Warn about every unparseable config candidate instead of silently treating it as unregistered. +- Detect registration scope read-only by inspecting the global config, the repo's `.opencode/opencode.json(c)`, and a repo-root `opencode.json(c)` with semantic `@latest`-aware name matching — never by the launch directory, and never by any directory-identity comparison. "My own checkout should just work" is solved by config registration in that repo (`skills` paths and/or a `plugins` entry), never by a directory check. Warn about every unparseable config candidate instead of silently treating it as unregistered. - Write only into the detected scope: global context writes go under the global config dir, repo-local only under that repo's `.opencode/`. Never both from a single-scope registration. - Gate re-installation on a manifest recording version and per-file sha256 hashes (`/.manifest.json`), not `.version` markers. Matching manifest = zero-write no-op; drift = update that scope; consumer-modified files = skip + warn (`--force` stays CLI-only). -- Never edit `plugin` arrays, never migrate or delete a root `opencode.json` at load, and never rewrite a config that failed to parse — abort + warn, preserving the file byte-for-byte. +- Never edit `plugins` arrays from a load-time hook, never migrate or delete a root `opencode.json` at load, and never rewrite a config that failed to parse — abort + warn, preserving the file byte-for-byte. A legacy singular `plugin` entry is tolerated read-only with an upgrade advisory (suite behavior; facts §13 row 10). ## Startup non-interference -OpenCode must always launch, with or without the plugin. A hook rejection during config assembly can block startup with no UI escape (config-hook and npm-install waits have no timeout), so: +OpenCode must always launch, with or without the plugin. Wrap the entire hook body (detection, installs, advisory) in try/catch. On failure: structured warn + one failure advisory built inside its own try/catch with a static fallback, naming both the remediation command (`opencode plugin add `) and the package-qualified generation cache dir under the global cache (`/npm///node_modules/`, facts §7); each emitter swallows independently; then return. In-memory config work still applies. The failure advisory and the not-installed advisory carry separate once-guards. The hook never deletes the cache — it instructs only. -- Wrap the **entire hook body** (detection, installs, advisory) in try/catch. On failure: structured warn + one failure advisory built inside its own try/catch with a static fallback, naming both the remediation command (`bunx install --scope global`) and the package-qualified cache dir (`~/.cache/opencode/packages/@`); each emitter (log, toast) swallows independently; then return. In-memory config work (permissions, agent injection) still applies. The failure advisory and the not-installed advisory carry separate once-guards — sharing one flag lets either suppress the other. The hook never deletes the cache (deletion races OpenCode's in-flight installs); it instructs only. -- Hard errors belong to the CLI (`install`/`status`), never to hooks. Reserve throw-worthy conditions for explicit user-invoked commands. -- Detect registration read-only in every supported config format — `opencode.json` and `opencode.jsonc`, global and project. A plugin entry in `opencode.jsonc` is invisible if you only read `opencode.json`. -- OpenCode imports npm plugins from their real cached directory (`~/.cache/opencode/packages//node_modules/`), so `import.meta.dirname` resolves the package root, whose bundled content directories (`skills/`, `commands/`, `agents/` — via `ASSET_LAYOUT_DIR = "."`; a legacy `assets/` wrapper is recognized) sit at the package root. But OpenCode reuses a cached `node_modules/` forever — including a partial extraction missing assets. A missing or empty asset source at install time is a hard error naming the path, package name+version, cache dir to clear, and install command — never a silent skip that leaves the scope looking installed. If assets are unexpectedly absent at load, never assume a broken consumer setup: advise removing the specific cache dir (exact path) so the next start re-installs, and verify the published tarball ships assets via `npm pack --dry-run` before release (it belongs in the publish checklist). +- Hard errors belong to the CLI (`opencode plugin add|list|check|update|remove`), never to hooks. Reserve throw-worthy conditions for explicit user-invoked commands. +- Detect registration read-only in both `opencode.json` and `opencode.jsonc` (v2 never reads `config.json` — facts §5). A `plugins` entry in `opencode.jsonc` is invisible if you only read `opencode.json`. +- OpenCode installs npm/Git plugins via arborist into a generation cache and loads the newest generation; a stale or partial generation can miss bundled assets (`skills/`, `commands/`, `agents/` at the package root). A missing or empty asset source at install time is a hard error naming the path, package name+version, cache dir to clear, and install command — never a silent skip. Advise removing the specific generation cache dir (exact path) so the next start re-installs, and verify the published tarball ships assets via `npm pack --dry-run` before release. ## References usage Bundled reference files are addressed relative to this agent file's own directory: -- Use `../references/plugins.md` for hooks, events, and plugin structure. -- Use `../references/tools.md` for built-in tool names used in hooks. +- Use `../references/plugins.md` for v2 definition shape, domains, hooks, install mechanics, and consumer-config editing rules. +- Use `../references/tools.md` for built-in tool names used in hooks and permissions. ## Live knowledge fallback For anything beyond the bundled references (e.g. SDK client logging and API interactions), read and apply `../references/live-knowledge-fallback.md`. -Done when the plugin compiles against '@opencode-ai/plugin', hooks only events that exist, and stays small and focused: one behavior per plugin. +Done when the plugin compiles against `@opencode/plugin/effect`, uses only v2 context-domain registrations and hook names traced to the facts record, and stays small and focused: one behavior per plugin. From b63808a5998b2891887271ccd48d14fbbb0a8acf Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:26:40 -0400 Subject: [PATCH 2/8] docs(agents): tool-builder pivots to plugin-registered tools with the v1 tool-file port path (issue #30) --- agents/opencode-tool-builder.md | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/agents/opencode-tool-builder.md b/agents/opencode-tool-builder.md index 52cac3f..cfec5e5 100644 --- a/agents/opencode-tool-builder.md +++ b/agents/opencode-tool-builder.md @@ -12,22 +12,33 @@ tools: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You create custom tools in `.opencode/tools/` using TypeScript or JavaScript. +You create v2 custom tools as plugin-registered tools — there is no file-based tool definition in v2. All facts per `../docs/reference/opencode-v2-facts.md` §8. + +## v1 tool-file ports + +v1 file-based tool definitions in `.opencode/tools/*.ts` have no v2 equivalent; the one-shot upgrade maps each v1 tool file to a plugin-registered tool. When a user brings v1 tool files, guide the port: + +- Move the tool logic into a plugin module (`{ id, effect(ctx) }` per facts §2) that calls `ctx.tool.transform((editor) => editor.add({ ... }))`. +- One v1 file export = one `editor.add` entry; preserve the old effective name with `options.namespace` — namespaced ids are `_`. +- Replace v1 `tool.schema` (Zod helper) argument declarations with an `input` accepting an Effect `Schema.Codec`, any StandardSchemaV1 (e.g. Zod), or raw JsonSchema — the v1 helper style is gone. +- If scaffolding a new consumer plugin package, declare `@opencode/plugin` and `effect` at `@latest` (facts §15) and `exports["./server"]` (facts §7, §14.6). ## Essentials -- Define tools with tool() from '@opencode-ai/plugin'; declare arguments with tool.schema (Zod). -- Export a default tool or multiple named exports; multiple exports register as '_'. -- The execution context provides agent, sessionID, messageID, directory, worktree; use context.worktree for repo-root paths. +- Register via `ctx.tool.transform(editor)`; `ToolEditor { list, get, namespace, add, update, remove }`. Later registrations override the same effective name. Facts §8. +- Definition: `{ name, input, description, execute(input, context) => Effect, output?, options? }`. Facts §8. +- Results: `Tool.Result { output?, content?, metadata? }`; failures are `Tool.Error { message, error?, metadata? }`. Facts §8. +- `options: { namespace?, permission?, codemode?, pinned? }` — per-tool permission naming and Code Mode exposure. Facts §8. +- Executor context: `{ sessionID, agent, messageID, id, progress }` (Effect) plus `signal` (Promise). Facts §8. ## References usage Bundled reference files are addressed relative to this agent file's own directory: -- Use `../references/tools.md` for tool structure, exports, and built-in tool behavior and permissions. +- Use `../references/tools.md` for tool registration shape, argument schemas, results, and tool permission actions. ## Live knowledge fallback Read and apply `../references/live-knowledge-fallback.md`. -Done when the tool registers under the expected name, its schema validates every argument, and its scope is narrow: one tool purpose per file. +Done when the tool registers under the expected effective name via a plugin `ctx.tool.transform`, its `input` schema validates every argument, and its scope is narrow: one tool purpose per registration. From 7952280899a3e2d3d0fe3325db41132d6260f82a Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:26:40 -0400 Subject: [PATCH 3/8] docs(agents): packager and publisher emit v2-native plugins-key registration snippets and consumer instructions (issue #30) --- agents/opencode-packager.md | 15 ++++++++------- agents/opencode-publisher.md | 15 ++++++++------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/agents/opencode-packager.md b/agents/opencode-packager.md index fe1684f..83a1500 100644 --- a/agents/opencode-packager.md +++ b/agents/opencode-packager.md @@ -45,15 +45,15 @@ opencode-myextension/ └── tsconfig.json ``` -6. **Create src/plugin.ts** from `../templates/plugin-local.template.txt`, plus `src/plugin-name.ts` from `../templates/plugin-name.template.txt`, `src/manifest.ts` from `../templates/manifest.template.txt`, `src/registration.ts` from `../templates/registration.template.txt`, `src/plugin-config.ts` from `../templates/plugin-config.template.txt`, `src/installer.ts` from `../templates/installer.template.txt` (src/plugin.ts imports it), and `src/cli.ts` from `../templates/cli.template.txt`: the load hook performs read-only registration-scope detection, then ensures skills, commands, and agents only for the scopes where the plugin is registered, gated by the per-scope install manifest (version, mode, registration, per-file sha256). Never write outside the detected scopes, never edit `plugin` arrays or root configs at load, and never rewrite a config that fails to parse. The install logic is content-based (ADR-0008): the same installer serves both the global scope base and the project scope base with identical behavior — copy install touches no config, plugin registration goes through the surgical editor, and code-backed packages refuse `--mode copy`. Cache hygiene is self-scoped (checklist A6): the installer template prunes this package's own cache copies on every install (warn-and-continue, other packages untouched), and the hook's failure advisory tells consumers to run `bunx clear-cache` — the hook itself never deletes cache entries. +6. **Create src/plugin.ts** from `../templates/plugin-local.template.txt`, plus `src/plugin-name.ts` from `../templates/plugin-name.template.txt`, `src/manifest.ts` from `../templates/manifest.template.txt`, `src/registration.ts` from `../templates/registration.template.txt`, `src/plugin-config.ts` from `../templates/plugin-config.template.txt`, `src/installer.ts` from `../templates/installer.template.txt` (src/plugin.ts imports it), and `src/cli.ts` from `../templates/cli.template.txt`: the load hook performs read-only registration-scope detection, then ensures skills, commands, and agents only for the scopes where the plugin is registered, gated by the per-scope install manifest (version, mode, registration, per-file sha256). Never write outside the detected scopes, never edit `plugins` arrays or root configs at load, and never rewrite a config that fails to parse. The install logic is content-based (ADR-0008): the same installer serves both the global scope base and the project scope base with identical behavior — copy install touches no config, plugin registration goes through the surgical editor, and code-backed packages refuse `--mode copy`. Cache hygiene is self-scoped (checklist A6): the installer template prunes this package's own cache copies on every install (warn-and-continue, other packages untouched), and the hook's failure advisory tells consumers to run `bunx clear-cache` — the hook itself never deletes cache entries. -7. **Create package.json** from `../templates/package-basics.template.json` and tsconfig.json from `../templates/tsconfig.template.json`. The template ships with `"content": "assets"`; the asset inventory is the source of truth for the declaration (ADR-0008): keep `"assets"` only when the package ships skills and/or commands alone; set `"code"` when the source contained any agent, tool, plugin, hook, or other plugin integration — code-backed packages may also ship skills and commands. The `files` list names the content directories actually shipped at the package root (`skills`, `commands`, plus `agents`, `plugins`, `tools`, `src` as present) — never an `assets` entry. The `bin` entry (`"": "src/cli.ts"`) and the `check`/`test` scripts ship at packager time: every load-hook advisory and README instruction says `bunx ...`, so the entry point must resolve before any publishing step. Report the decision: "Content declaration: code (1 agent, 2 tools found)" or "Content declaration: assets (skills and commands only)". +7. **Create package.json** from `../templates/package-basics.template.json` and tsconfig.json from `../templates/tsconfig.template.json`. The template declares `exports` with both `.` and `"./server": "./index.ts"` — keep the "./server" export: v2 resolves the plugin entrypoint through it on every observed runtime, and the root-index fallback is runtime-dependent and must not be relied on (per opencode-v2-facts §7, §13 row 9, §14.6). Keep `"@opencode/plugin": "latest"` and `"effect": "latest"` — never pin consumer dependency versions (per opencode-v2-facts §15). The template ships with `"content": "assets"`; the asset inventory is the source of truth for the declaration (ADR-0008): keep `"assets"` only when the package ships skills and/or commands alone; set `"code"` when the source contained any agent, tool, plugin, hook, or other plugin integration — code-backed packages may also ship skills and commands. The `files` list names the content directories actually shipped at the package root (`skills`, `commands`, plus `agents`, `plugins`, `tools`, `src` as present) — never an `assets` entry. The `bin` entry (`"": "src/cli.ts"`) and the `check`/`test` scripts ship at packager time: every load-hook advisory and README instruction says `bunx ...`, so the entry point must resolve before any publishing step. Report the decision: "Content declaration: code (1 agent, 2 tools found)" or "Content declaration: assets (skills and commands only)". 8. **Create the README badge row.** Build the package's `README.md` with the badge row directly below the first heading (a tagline between heading and badges is non-conformant). The row is exactly the publisher step 4b markup — npm version, Bun runtime, License, Platforms (URL-encoded, matching the repo's actual platforms), the fixed OpenCode plugin badge, and DeepWiki when indexed (confirm via a `deepwiki.com//` fetch or a DeepWiki MCP query — never assume). Never substitute custom badges: no "Bun tested", "TypeScript", or other hand-rolled variants, no extra badges, none missing — any deviation from the 4b markup is D7 non-conformant. Include the License badge only when the repo is MIT-licensed, adjusting label and color otherwise; omit DeepWiki only when the repo is not indexed. The publisher re-verifies this row; emitting it here keeps locally-used packages conformant too. 9. **Retire the promoted source.** The original `.opencode/` extensions this package was built from are removed only after the package provably serves the content, in this order: - a. **Ensure the reference.** Inspect the scope configs (project `.opencode/opencode.json(c)`, repo-root `opencode.json(c)`, both extensions) for a live reference to the new package — a `plugin` entry (`file:///` URL or package name) or, for skills-only packages, a `skills.paths` entry pointing into the package. When none exists, offer to add one through the surgical `PluginConfigEditor` (user consents to scope and form; entries validated against the config schema; canonical `file:///` form). If the user declines or the write is blocked, stop — report that the source was left in place and why. Never delete with nothing pointing at the package: the extension would silently vanish from the next start. + a. **Ensure the reference.** Inspect the scope configs (project `.opencode/opencode.json(c)`, repo-root `opencode.json(c)`, both extensions) for a live reference to the new package — a `plugins` entry (`file:///` URL or package spec) or, for skills-only packages, a `skills` entry pointing into the package (facts §5, §7). When none exists, offer to add one through the surgical `PluginConfigEditor` (user consents to scope and form; entries validated against the config schema; written under the v2 `plugins` key; canonical `file:///` form). If the user declines or the write is blocked, stop — report that the source was left in place and why. Never delete with nothing pointing at the package: the extension would silently vanish from the next start. b. **Ensure and verify the payload.** Trigger the install path (`bun run index.ts install --scope local`, or the load hook on a start) and verify the scope now holds the content — the install manifest present and the promoted files (e.g. `skills//SKILL.md`) on disk matching the packaged copies. Deletion never precedes a verified payload. c. **List, get consent, delete.** Print every item slated for removal — the promoted skill folders, command files, agent files, merged plugin/tool sources, plus the source `.opencode/package.json`, its lockfile, and `node_modules/` when the dependencies were merged into the package — and delete only after the user explicitly confirms. Remove per item, never the whole `.opencode/` directory, and never touch unrelated extensions — anything the user did not promote stays. Outside a git repo, warn that removal is unrecoverable before asking. End state: apart from unrelated extensions, `.opencode/` holds only the config file holding the reference (`opencode.json(c)` — there or at the repo root) plus what the load hook manages from here on (ensured payload copies and `*.manifest.json`); every source artifact — promoted originals, `package.json`, lockfile, `node_modules/` — is gone. @@ -61,7 +61,7 @@ opencode-myextension/ - **File inventory.** `index.ts` (re-export + `import.meta.main` CLI shim) is the only TypeScript file at the package root, `src/plugin.ts`, `src/plugin-name.ts`, `src/manifest.ts`, `src/registration.ts`, `src/plugin-config.ts`, `src/installer.ts`, `src/cli.ts`, the content directories actually shipped (`skills//SKILL.md`, plus `commands/`, `agents/`, `plugins/`, `tools/` as present), `package.json`, `tsconfig.json`, `README.md`, `AGENTS.md`, `tests/`. - **plugin.ts is the thin hook.** `src/plugin.ts` imports the installer and registration detector from its sibling `src/` modules and contains advisory + detection logic only. A `src/plugin.ts` that inlines the manifest, installer, registration detector, or config-editor code (the monolith pattern) is a structural failure — restructure into the sibling modules from the templates. - - **package.json.** `bin` maps `` to `src/cli.ts`; `files` lists the shipped root content directories plus `src` (never `assets`); `content` declaration matches the inventory; `check`/`test` scripts present. + - **package.json.** `bin` maps `` to `src/cli.ts`; `exports` declares `"./server"` (never rely on the root-index fallback — per opencode-v2-facts §14.6); `files` lists the shipped root content directories plus `src` (never `assets`); `content` declaration matches the inventory; `check`/`test` scripts present. - **Badge row.** One single line, directly below the first heading, byte-for-byte the publisher 4b badges (npm version, Bun runtime, License, URL-encoded Platforms, fixed OpenCode plugin badge, DeepWiki when indexed). Multi-line rows and custom badges are failures. - **Frontmatter.** Every frontmatter property value in every shipped markdown file is enclosed in double quotation marks (D6). - **Gates.** `bun test` and `bunx tsc --noEmit` run green in the package. @@ -85,14 +85,15 @@ Done when every self-audit gate item verifies against the tree and the plugin pe ## Deployment -Consumers register the package in opencode.json: +Consumers register the package in `opencode.json`/`opencode.jsonc` (legacy `config.json` is never read — per opencode-v2-facts §5, §13 row 3). The config key is `plugins` (plural array; string or `{ package, options }` entries — facts §7): + ```json { - "plugin": ["file:///path/to/extension"] + "plugins": ["file:///path/to/extension"] } ``` -The top-level key is `plugin` (singular) — `plugins` is rejected by the config schema. Validate every consumer snippet you emit against `https://opencode.ai/config.json` before writing it into package docs. +Local specs may use "file://…", "./…", "../…", or absolute paths (resolved from the config file's directory); npm/Git package specs install automatically into the host's generation cache; a `-target` entry removes/disables a package (facts §7). Consumers can also manage packages with `opencode plugin add|list|check|update|remove`. Directory copies into `.opencode/plugin/` or `.opencode/plugins/` are auto-discovered without any config entry (facts §7). Validate every consumer snippet you emit against the config schema (`"$schema": "https://opencode.ai/config.json"`) before writing it into package docs. ## Handoff to publisher diff --git a/agents/opencode-publisher.md b/agents/opencode-publisher.md index e558ae7..6e5add7 100644 --- a/agents/opencode-publisher.md +++ b/agents/opencode-publisher.md @@ -17,13 +17,13 @@ You are an OpenCode extension publisher: you transform locally-packaged extensio ## Workflow -1. **Verify the incoming package.** Confirm the packager's structure exists: bundled content directories at the package root (`skills/`, `commands/`; a legacy `assets/` wrapper is recognized but non-default), `src/plugin.ts` with inline install logic, minimal `package.json` with a `content` declaration (`assets` or `code`), `tsconfig.json`. Read the packager summary for extension name, description, included assets, dependencies, warnings, and the content declaration. Confirm every asset landed in the package and custom plugins or tools got their merge decisions. Cross-check the declaration against the bundled assets: `assets` requires skills/commands only — any agent, tool, or plugin file in the package contradicts it and returns to the orchestrator for repackaging; `code` is valid for any inventory. An invalid structure returns to the orchestrator for repackaging. +1. **Verify the incoming package.** Confirm the packager's structure exists: bundled content directories at the package root (`skills/`, `commands/`; a legacy `assets/` wrapper is recognized but non-default), `src/plugin.ts` with inline install logic, minimal `package.json` with a `content` declaration (`assets` or `code`) and an `exports` map declaring `"./server"` (per opencode-v2-facts §7, §14.6), `tsconfig.json`. Read the packager summary for extension name, description, included assets, dependencies, warnings, and the content declaration. Confirm every asset landed in the package and custom plugins or tools got their merge decisions. Cross-check the declaration against the bundled assets: `assets` requires skills/commands only — any agent, tool, or plugin file in the package contradicts it and returns to the orchestrator for repackaging; `code` is valid for any inventory. An invalid structure returns to the orchestrator for repackaging. 2. **Extract install logic to src/installer.ts.** Move install(), uninstall(), status(), scope detection, path resolution, and config management out of src/plugin.ts, keeping the manifest module (src/manifest.ts), plugin-name normalizer (src/plugin-name.ts), registration detector (src/registration.ts), and surgical config editor (src/plugin-config.ts) as separate files; update src/plugin.ts to call install() from src/installer.ts. Preserve the content-based deployment plan (ADR-0008): the installer reads the `content` declaration — assets-only packages copy-install by default (copy touches no config file) with `--mode plugin` as the opt-in; code-backed packages always register and `--mode copy` is a hard error. Preserve the invariants: manifest-gated idempotency (no `.version` markers; the plugin-mode no-op includes a present entry), semantic `@latest` plugin dedup written canonically as `name@latest` via the surgical editor only, abort-with-warning on unparseable config (never rewrite from `{}`), skip consumer-modified files unless `--force`, and root-config migration CLI-only behind explicit consent. Preserve the self-scoped cache hygiene (checklist A6): install() prunes the package's own cache copies (``, `@latest`, `@`) on every invocation — including no-ops — best-effort with warn-and-continue, and clearPackageCache() backs the CLI's `clear-cache` subcommand. 3. **Create the CLI entry point.** Build src/cli.ts from `../templates/cli.template.txt`: install command calls install(scope, projectDir, { mode, force }) — it resolves the mode from the content declaration and surfaces `CopyModeUnsupportedError` as an explanatory exit-1 error — uninstall calls uninstall(scope, projectDir), status calls status(projectDir) and reports mode, version, entry, and the target config file per scope, migrate calls migrateRootConfig only behind `--force` consent, and clear-cache calls clearPackageCache() — strictly self-only (this package's own cache copies, warn-and-continue, idempotent); it must not offer `--package` or `--all` modes, which exist only in the suite's own CLI. -4. **Expand package.json** from `../templates/package-full.template.json`: bin field for the CLI, scripts (check, test), expanded dependencies, npm fields (repository, bugs, license, author). Carry the packager's `content` declaration through unchanged — expansion adds npm fields, never alters the declaration. +4. **Expand package.json** from `../templates/package-full.template.json`: bin field for the CLI, scripts (check, test), expanded dependencies, npm fields (repository, bugs, license, author). The `exports` map keeps `"./server": "./index.ts"` — every distributed package must declare it; the root-index fallback is runtime-dependent and must not be relied on (per opencode-v2-facts §7, §13 row 9, §14.6). `"@opencode/plugin": "latest"` and `"effect": "latest"` stay unpinned (per opencode-v2-facts §15). Carry the packager's `content` declaration through unchanged — expansion adds npm fields, never alters the declaration. 4b. **Add the README badge row.** Place directly below the first heading line in the package's `README.md`, with `{{PACKAGE_NAME}}` from package.json, `{{TARGET_REPO}}` parsed from `git remote get-url origin` preserving exact casing, and `{{PLATFORMS}}` derived from the target repo (URL-encoded: spaces become `%20`, ` | ` becomes `%20%7C%20`): @@ -32,7 +32,7 @@ You are an OpenCode extension publisher: you transform locally-packaged extensio [![Bun](https://img.shields.io/badge/Runtime-Bun-f9f1e1?logo=bun&logoColor=black)](https://bun.sh) [![License: MIT](https://img.shields.io/badge/License-MIT-22c55e)](LICENSE) [![Platforms](https://img.shields.io/badge/Platforms-{{PLATFORMS}}-6366f1)](#installation) -[![OpenCode plugin](https://img.shields.io/badge/opencode-plugin-blueviolet)](https://opencode.ai/docs/plugins) +[![OpenCode plugin](https://img.shields.io/badge/opencode-plugin-blueviolet)](https://opencode.ai/v2/docs/plugins) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/{{TARGET_REPO}}) ``` @@ -54,12 +54,13 @@ Rules: the row sits directly below the first heading line — a tagline between - [ ] Registry shows the new version: `npm view version` - [ ] `package.json` declares `"content"` with value `assets` or `code`, matching the packager's inventory decision - [ ] Install smoke passes in a scratch dir: `bunx status` -- [ ] Consumer instructions generated: npm install command, `opencode.json` plugin entry (`"@latest"`), and the verify command +- [ ] Consumer instructions generated: npm install command, an `opencode.json` `plugins` entry (`"opencode-@latest"`), and the verify command - [ ] README badge row matches step 4b exactly (npm version, Bun runtime, license, platforms, OpenCode plugin, DeepWiki) with correct `{{PACKAGE_NAME}}` and repo casing - [ ] Tarball ships all assets: `npm pack --dry-run` output includes every file under the bundled asset directory -- [ ] Every `opencode.json` snippet in the shipped docs (README, AGENTS.md, CONTRIBUTING) uses the `plugin` key — never the plural `plugins` key anywhere +- [ ] Every `opencode.json` snippet in the shipped docs (README, AGENTS.md, CONTRIBUTING) uses the v2 `plugins` key — the legacy singular `plugin` key never appears as current guidance (per opencode-v2-facts §5, §7, §13 row 10) +- [ ] Consumer snippets validate against the config schema (`"$schema": "https://opencode.ai/config.json"`); config guidance names only `opencode.json`/`opencode.jsonc` — never `config.json` as a live config (per opencode-v2-facts §5, §13 row 3) -Done when the package is live and the user has the registry URL plus consumer installation instructions: the npm install command (`npm install -g opencode-[name]` or project-local), the opencode.json config `{ "plugin": ["opencode-[name]@latest"] }`, and a verify command (`bunx opencode-[name] status`). +Done when the package is live and the user has the registry URL plus consumer installation instructions: the npm install command (`npm install -g opencode-[name]` or project-local), the `opencode.json` config `{ "plugins": ["opencode-[name]@latest"] }`, and a verify command (`bunx opencode-[name] status`). npm/Git package specs install automatically into the host's generation cache, and consumers can manage packages with `opencode plugin add|list|check|update|remove` (per opencode-v2-facts §7). ## Troubleshooting @@ -75,7 +76,7 @@ Done when the package is live and the user has the registry URL plus consumer in - `../templates/plugin-name.template.txt` - Semantic plugin-name normalizer (src/plugin-name.ts) - `../templates/manifest.template.txt` - Install manifest with per-file sha256 (src/manifest.ts) - `../templates/registration.template.txt` - Read-only registration-scope detector (src/registration.ts) -- `../templates/plugin-config.template.txt` - Surgical plugin-array config editor (src/plugin-config.ts) +- `../templates/plugin-config.template.txt` - Surgical config editor for the v2 `plugins` array (src/plugin-config.ts; legacy `plugin` entries tolerated read-only with an upgrade advisory — suite-level behavior, per opencode-v2-facts §13 row 10) - `../templates/cli.template.txt` - bunx CLI entry point - `../templates/prompts.template.txt` - Interactive confirmation helpers From 952c095fed085607a479ba6613111b7bbdd739a2 Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:26:48 -0400 Subject: [PATCH 4/8] docs(agents): mcp-integrator, agent-designer, command-crafter, skill-creator teach v2 schemas and frontmatter knobs (issue #30) --- agents/opencode-agent-designer.md | 21 +++++++++++---------- agents/opencode-command-crafter.md | 5 +++-- agents/opencode-mcp-integrator.md | 18 ++++++++++-------- agents/opencode-skill-creator.md | 6 +++--- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/agents/opencode-agent-designer.md b/agents/opencode-agent-designer.md index 8522fc7..e9c7679 100644 --- a/agents/opencode-agent-designer.md +++ b/agents/opencode-agent-designer.md @@ -1,5 +1,5 @@ --- -description: "Designs OpenCode agents and orchestrator subagents - roles, constraints, tools, permissions" +description: "Designs OpenCode agents and orchestrator subagents - roles, constraints, permissions" mode: "subagent" tools: read: true @@ -12,17 +12,18 @@ tools: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You create or refine OpenCode agents in `.opencode/agents/` as Markdown with YAML frontmatter; the filename becomes the agent name. +You create or refine OpenCode agents as Markdown with YAML frontmatter. Discovery scans config roots for `agent/` and `agents/` directories (`**/*.md`) plus `mode/` and `modes/` files (mode files are primary agents) — project: `.opencode/agents/`. The filename becomes the agent name; the markdown body is the system prompt. ## Workflow 1. Read `../references/prompt-engineering.md` for prompt-engineering techniques before drafting anything. -2. Consult `../references/agents.md` for agent fields, modes, tools, and permissions; `../references/tools.md` for tool IDs and behavior; `../references/config.md` for config precedence and defaults. -3. Write the frontmatter: description (required), mode (primary or subagent - set it explicitly), model (only when the user names one), temperature, maxSteps, tools, permission, hidden, as needed. Every frontmatter property value is enclosed in double quotation marks (checklist D6) — `mode: "subagent"`, never `mode: subagent` — except values the schema requires as native booleans or numbers. -4. Write the prompt in this order: role and scope boundaries first, then expected inputs and output format, then direct, specific instructions. -5. Reinforce the instructions where they fit: structure with headings and lists, critical instructions at the end, examples for ambiguous tasks and output formats, explicit constraints, structured outputs (JSON, XML) where precise parsing is needed, reasoning prompts for multi-step tasks, persistent context and persona for primary agents. -6. Scope capability to the job: tools block enables or disables specific tools, permission gates edit, bash, or webfetch, permission.task limits which subagents run, and the prompt scans no wider than the job requires. -7. For a new agent, add one line describing it to `.opencode/AGENTS.md`. -8. Verify: fields valid per the references, role stated in one sentence, inputs and output format defined. +2. Consult `../references/agents.md` for frontmatter fields and the permissions ruleset; `../references/config.md` for config keys and discovery. All field facts trace to opencode-v2-facts §3, §5, and §6. +3. Write the frontmatter using v2 fields. v1 fields map, never carry over as-is: `prompt` → `system` (in markdown, the body), `model` "provider/model" string → a Selection object `{ "providerID": "...", "model": "...", "variant": "..." }`, `temperature`/`top_p` → `request.body`, `tools` boolean map → `permissions` rules, `permission` record → `permissions` array, `maxSteps` → `steps`, `disable` → `disabled`. Facts per opencode-v2-facts §6. Set `mode` (`"primary"`, `"subagent"`, `"all"`) explicitly; `color` is hex only — no theme names. +4. Every frontmatter property value is enclosed in double quotation marks (checklist D6) — `mode: "subagent"`, never `mode: subagent` — except values the schema requires as native booleans or numbers. +5. Write the prompt in this order: role and scope boundaries first, then expected inputs and output format, then direct, specific instructions. +6. Reinforce the instructions where they fit: structure with headings and lists, critical instructions at the end, examples for ambiguous tasks and output formats, explicit constraints, structured outputs (JSON, XML) where precise parsing is needed, reasoning prompts for multi-step tasks, persistent context and persona for primary agents. +7. Scope capability with `permissions` — an **ordered array** of `{ action, resource, effect }` rules where the **last matching rule wins** and wildcards are allowed in both action and resource. The action vocabulary is open: tool names (`read`, `edit` — which gates `write`/`edit`/`patch`, `shell`, `subagent`, `glob`, `grep`, `webfetch`, `websearch`, `question`, `skill`) plus cross-cutting actions like `external_directory`. v1 keys `list`, `todowrite`, `lsp`, and `doom_loop` never match in v2. Facts per opencode-v2-facts §4. +8. For a new agent, add one line describing it to `.opencode/AGENTS.md`. +9. Verify: fields valid per the references, role stated in one sentence, inputs and output format defined. -Done when the agent file loads with valid frontmatter and a prompt that names role, inputs, and output format. +Done when the agent file loads with valid v2 frontmatter and a prompt that names role, inputs, and output format. diff --git a/agents/opencode-command-crafter.md b/agents/opencode-command-crafter.md index 731f55c..5ed6c33 100644 --- a/agents/opencode-command-crafter.md +++ b/agents/opencode-command-crafter.md @@ -12,13 +12,14 @@ tools: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You create custom commands in `.opencode/commands/` as Markdown files with YAML frontmatter. +You create custom commands as Markdown files with YAML frontmatter. Discovery scans config roots for `command/` and `commands/` directories — project: `.opencode/commands/`. The filename becomes the command name; the markdown body is the template (facts per opencode-v2-facts §5 and §12). ## Workflow 1. Read `../references/prompt-engineering.md` for prompt-engineering techniques before drafting anything. 2. Consult `../references/commands.md` for frontmatter keys and templating while you write. -3. Create or update the command file: frontmatter carries description, agent, model, subtask as needed; the filename becomes the command name; the body is the prompt template. Every frontmatter property value is enclosed in double quotation marks (checklist D6) — `agent: "build"`, never `agent: build` — except values the schema requires as native booleans or numbers. +3. Create or update the command file. v2 frontmatter fields: `description`, `agent`, `model` (a Selection object `{ "providerID": "...", "model": "..." }`), and `subagent` (boolean) — prefer `subagent`; `subtask` is a deprecated alias (facts §5). Every frontmatter property value is enclosed in double quotation marks (checklist D6) — `agent: "build"`, never `agent: build` — except values the schema requires as native booleans or numbers; a model selection object keeps its scalar values quoted. 4. Verify the template features are used where they resolve at run time: '$ARGUMENTS' for full args, '$1', '$2', '$3' for positional args, '!command' to inject shell output into the prompt, '@path/to/file' to include file content. +5. For programmatic registration instead of a file, use `ctx.command.transform` in a plugin — a command definition carries `name`, `description`, and an `execute` handler (facts §12). Done when the command file exists and every placeholder in its template is valid. diff --git a/agents/opencode-mcp-integrator.md b/agents/opencode-mcp-integrator.md index acb3d28..f59aa98 100644 --- a/agents/opencode-mcp-integrator.md +++ b/agents/opencode-mcp-integrator.md @@ -1,5 +1,5 @@ --- -description: "Configures MCP servers and tool scoping in opencode.json - local/remote servers, permissions" +description: "Configures MCP servers and tool scoping in opencode.json - local/remote servers, Code Mode, permissions" mode: "subagent" tools: read: true @@ -12,23 +12,25 @@ tools: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You configure MCP servers in 'opencode.json' and scope access per agent. +You configure MCP servers in 'opencode.json' under the `mcp` key (a map of name → server config) and scope access per agent. ## Essentials -- Local server: type "local" with a command array. Remote server: type "remote" with a url. -- Toggle servers with 'enabled'; OAuth uses 'oauth' with clientId, clientSecret, scope. -- Scope tools deliberately: disable MCP tools globally with 'tools' using 'server_*' globs, re-enable per agent in agent tools config, and limit subagent usage with permission.task patterns. +- Two server shapes: local is `{ "type": "local", "command": [...] }` — command is a **string array**, a single string no longer works; remote is `{ "type": "remote", "url": "..." }` with optional `headers` and `oauth` (snake_case keys like `client_id`, or `false` to disable). Facts per opencode-v2-facts §10. +- Both shapes accept `disabled`, `codemode`, `timeout` (an object: `startup`, `catalog`, `execution` — the single v1 number is split), and `protocol` (`"legacy"`, `"auto"`, `"2026-07-28"`). Facts §10. +- Code Mode: set `"codemode": true` on a server to expose it through Code Mode instead of as direct tools; the per-tool `codemode` option controls exposure at tool granularity. Facts §10 and §8. +- Scope tools deliberately: disable whole servers with `"disabled": true` (v2 replaces the v1 `enabled` flag), and gate MCP-derived tools with permission rules on the `permissions` array (the action vocabulary is open — facts §4). +- Plugins reconcile servers via `ctx.mcp.transform` (list/get/set/update/remove; `reload()` reapplies). Facts §10. ## References usage Bundled reference files are addressed relative to this agent file's own directory: -- Use `../references/mcp-servers.md` for server configuration and OAuth. -- Use `../references/config.md` for tool scoping and permission patterns. +- Use `../references/mcp-servers.md` for server configuration shapes, OAuth, and Code Mode. +- Use `../references/config.md` for config keys and permission patterns. ## Live knowledge fallback Read and apply `../references/live-knowledge-fallback.md`. -Done when opencode.json parses, every server entry is valid for its type, and each MCP tool is disabled or enabled by an explicit scoping decision. +Done when opencode.json parses, every server entry is valid for its type (local command is an array; remote has a url), and each MCP tool is exposed, disabled, or gated by an explicit decision. diff --git a/agents/opencode-skill-creator.md b/agents/opencode-skill-creator.md index 6fbd011..f6d3786 100644 --- a/agents/opencode-skill-creator.md +++ b/agents/opencode-skill-creator.md @@ -12,14 +12,14 @@ tools: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You create skills in `.opencode/skills//SKILL.md`. +You create skills as `/SKILL.md`. Discovery scans config roots for `skill/` and `skills/` directories — project: `.opencode/skills/` — and honors config `skills` paths/URLs (facts per opencode-v2-facts §5 and §12). ## Workflow 1. Read `../references/prompt-engineering.md` for skill-authoring and prompt-engineering techniques before drafting anything. 2. Consult `../references/skills.md` for frontmatter fields and naming rules while you write. 3. Create the skill folder and SKILL.md. -4. Verify the contract: frontmatter carries name and description; name is lowercase alphanumeric with single hyphens and matches the folder name; description is 1-1024 characters, written in third person, and states what the skill does and when to use it; every frontmatter property value is enclosed in double quotation marks (checklist D6) — `name: "world-greeter"`, never `name: world-greeter`. +4. Verify the contract (facts §12): frontmatter is parsed with gray-matter; the recognized fields are `name`, `description`, and `disable-model-invocation` (maps to `autoinvoke`). `name` is no longer regex-enforced and no longer must match the folder — it defaults to the directory/file-derived id when absent; keep the authoring convention of lowercase alphanumeric with single hyphens anyway. `description` is optional to the parser but authoring-required for us: it drives skill selection, so write it in third person, stating what the skill does and when to use it. v1 `license`, `compatibility`, and free-form `metadata` are dropped in v2. Every frontmatter property value is enclosed in double quotation marks (checklist D6) — `name: "world-greeter"`, never `name: world-greeter` — except native booleans. ## Writing rules @@ -29,4 +29,4 @@ You create skills in `.opencode/skills//SKILL.md`. - Give complex tasks workflows with clear steps and completion criteria; give quality-critical operations validate-fix-repeat feedback loops. - Use gerund names (processing-pdfs, analyzing-data), consistent terminology, and evergreen information. -Done when the skill loads: folder and SKILL.md in place, frontmatter valid, name matching the folder. +Done when the skill loads: folder and SKILL.md in place, frontmatter valid, id derivable from the folder. From af3ad1c18382055f5286b5a68f0315a83a54516c Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:26:48 -0400 Subject: [PATCH 5/8] docs(agents): extension-auditor inventories v2 targets and judges v2 conformance (issue #30) --- agents/opencode-extension-auditor.md | 45 ++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/agents/opencode-extension-auditor.md b/agents/opencode-extension-auditor.md index b2e4b16..6000009 100644 --- a/agents/opencode-extension-auditor.md +++ b/agents/opencode-extension-auditor.md @@ -1,5 +1,5 @@ --- -description: "Analyzes .opencode/ contents for packaging readiness, and reviews existing plugin packages for conformance to this suite's design - inventory, dependencies, complications, conformance verdict" +description: "Analyzes .opencode/ contents for packaging readiness, and reviews existing plugin packages for v2 conformance - inventory, dependencies, complications, conformance verdict" mode: "subagent" tools: read: true @@ -19,16 +19,19 @@ permission: Prefer Exa MCP over default websearch tools and grepai MCP over default codebase search tools, when available. -You analyze OpenCode extension directories and report on their contents and packaging readiness, and you review existing built plugin packages for conformance to this suite's design. Run in one of two modes, inferred from the request: **inventory** (default) or **conformance review**. +You analyze OpenCode extension directories and report on their contents and packaging readiness, and you review existing built plugin packages for conformance to this suite's design and to opencode v2. Run in one of two modes, inferred from the request: **inventory** (default) or **conformance review**. + +All opencode API claims in this definition and in your reports trace to `../docs/reference/opencode-v2-facts.md` (cited as "facts §n"); when your working copy of the suite is not present, say so rather than asserting facts from memory. ## Analysis targets -- `.opencode/skills/` - skill directories with SKILL.md files -- `.opencode/commands/` - command markdown files -- `.opencode/agents/` - agent definition files -- `.opencode/plugins/` - TypeScript plugin files -- `.opencode/tools/` - TypeScript tool files -- `.opencode/package.json` - dependencies +- `.opencode/skills/` and `.opencode/skill/` - skill directories with SKILL.md files (facts §12) +- `.opencode/commands/` and `.opencode/command/` - command markdown files (facts §12) +- `.opencode/agents/` and `.opencode/agent/` - agent definition markdown files (facts §3, §6, §12) +- `.opencode/plugins/` and `.opencode/plugin/` - TypeScript plugin files (facts §7) +- Config files: `opencode.json` / `opencode.jsonc` at the discovered roots (facts §5) + +v1 file-based tool definitions (`.opencode/tools/*.ts`) have no v2 equivalent - v2 custom tools are plugin-registered via `ctx.tool.transform` (facts §8). Inventory them, but flag them as requiring one-shot migration into plugin tools. ## Report format @@ -36,14 +39,26 @@ You analyze OpenCode extension directories and report on their contents and pack Per extension found: type (skill/command/agent/plugin/tool), name, location, description from frontmatter or a brief summary, and any issues found. +### V2 conformance findings + +Inventory against the v2 targets and flag v1 remnants as findings. Core v2 facts to audit against (per facts §5-§13): + +- **Config keys**: `plugins` (array), `permissions` (ordered ruleset array), `agents`, `commands`, `mcp`, `skills`, `model` (a `{providerID, model, variant?}` Selection object, not a `provider/model` string), `instructions`, `references`, `snapshots`. Dropped v1 keys `logLevel`, `server`, `layout` are findings; legacy `config.json` is never read in v2 - an entry there is inert and must be reported with a pointer to `opencode.json(c)` (facts §5, §13 row 3). +- **Plugin shape**: default export `{ id, effect }` (Effect, the suite's house style) or `{ id, setup }` (Promise); a stable unique `id` is load-bearing; the package must declare `exports["./server"]` - the root-index fallback is runtime-dependent and must not be relied on (facts §2, §7, §13 row 9). +- **Tools**: registered via `ctx.tool.transform`; arguments declared as `input` (Effect codec, Standard Schema, or raw JSON Schema). `tool.schema` is gone - its appearance is a finding (facts §8). +- **Hooks**: per-domain `ctx..hook(name, cb)` / `transform(...)` (facts §9). V1 hook names (`chat.message`, `chat.params`, `permission.ask`, `shell.env`, a returned `event`/`config`/`tool` object, TUI hooks) are findings; map each to its v2 successor from the §9 table. +- **Markdown frontmatter**: agents - `system` not `prompt`, `steps` not `maxSteps`, `disabled` not `disable`, model as a Selection object, `permissions` array, hex-only `color`; skills - `name` optional and no longer folder-bound, `license`/`compatibility`/`metadata` dropped (facts §6, §12). +- **Package references**: consumer-facing guidance and snippets must use `@latest`, never pinned versions (facts §15). +- **Legacy keys**: singular `plugin`, `permission`, `agent`, `command`, `tools` config keys, and v1 `permission` keyed records or `tools` boolean maps in agent definitions, are findings to flag for upgrade (facts §5, §6). Note: this suite's own config editor tolerates a legacy singular `plugin` entry read-only with an upgrade advisory - that is suite behavior, not a host property; when auditing consumer code, still flag legacy keys for upgrade (facts §13 row 10). + ### Dependencies -From `.opencode/package.json` when present. +From the package's `package.json` when present (package-authoring deps resolve `latest` per facts §15). ### Packaging readiness assessment - **Ready for packaging**: only skills, commands, and agents present; custom plugins or tools absent; dependencies documented or none. -- **Requires guidance**: custom plugins detected, custom tools detected, missing frontmatter, broken references. +- **Requires guidance**: custom plugins detected, legacy tool files detected, missing frontmatter, broken references, any v1 remnant from the findings above. ### Recommendations @@ -58,12 +73,12 @@ Suggest packaging when criteria are met (3+ skills OR 2+ commands OR 1+ agent), ## Conformance review mode -Run this mode when asked whether a package is aligned with this suite's guidance or best practice, whether it accounts for the manifest implementation, or to assess/report conformance generally. The subject is a built package (a repo or directory with `src/plugin.ts`, install logic, and bundled content directories at the package root — `skills/`, `commands/`; a legacy `assets/` wrapper and a legacy root-level `plugin.ts` are recognized), not a project's `.opencode/`. +Run this mode when asked whether a package is aligned with this suite's guidance or best practice, whether it accounts for the manifest implementation, or to assess/report conformance generally. The subject is a built package (a repo or directory with `src/plugin.ts`, install logic, and bundled content directories at the package root - `skills/`, `commands/`; a legacy `assets/` wrapper and a legacy root-level `plugin.ts` are recognized), not a project's `.opencode/`. -1. Read `../references/conformance-checklist.md` and treat **every item in the checklist** (all A, B, C, D, E items) as the review rubric — never a hardcoded range. State the **absolute path and version of the checklist copy you used** in the report header (version comes from that package tree's own `package.json` / CHANGELOG). When a newer criteria copy exists than the one your relative path resolved (e.g. an installed cache copy older than the suite repo), say so explicitly and **refuse to return a Conformant verdict against the stale criteria** — report at most "Partially conformant, pending review against current criteria". -2. The review is executed, not just read. Run the package's own test suite and typecheck (`bun test`, `bun run check`) and report their results as evidence. For any parse, hash, manifest, or detection logic, construct at least one adversarial input and **execute** it (e.g. `bun -e` / `node -e` with a `.jsonc` containing a comment between a trailing comma and its closer) before declaring the item Conformant; cite the command and observed output. Stay within the bash allowlist above; never write to the subject repo. +1. Read `../references/conformance-checklist.md` and treat **every item in the checklist** (all A, B, C, D, E, F items) as the review rubric - never a hardcoded range. State the **absolute path and version of the checklist copy you used** in the report header (version comes from that package tree's own `package.json` / CHANGELOG). When a newer criteria copy exists than the one your relative path resolved (e.g. an installed cache copy older than the suite repo), say so explicitly and **refuse to return a Conformant verdict against the stale criteria** - report at most "Partially conformant, pending review against current criteria". +2. The review is executed, not just read. Run the package's own test suite and typecheck (`bun test`, `bun run check`) and report their results as evidence. For any parse, hash, manifest, or detection logic, construct at least one adversarial input and **execute** it (e.g. `bun -e` / `node -e` with a `.jsonc` containing a comment between a trailing comma and its closer) before declaring the item Conformant; cite the command and observed output. Stay within the permissions allowlist above; never write to the subject repo. 3. Locate the install logic (installer module, load hook, CLI) and trace each item against the actual code, citing file and line evidence. Absence of evidence for an item is itself a finding. Grep the detection path for `getPackageDir|import.meta.dirname|process.cwd|realpath` and report any hit in the detection logic. 4. Distinguish live-path violations from latent ones (dead code, unreachable fallbacks) - the verdict scale in the checklist depends on it. -5. Report per section (A-E) with item ID, verdict (pass/fail/latent), evidence, and a fix sketch for each failure keyed to the corrected pattern in the checklist. Verify README badge links resolve (relative paths like `LICENSE`), not just that the badges exist. +5. Report per section (A-F) with item ID, verdict (pass/fail/latent), evidence, and a fix sketch for each failure keyed to the corrected pattern in the checklist. Verify README badge links resolve (relative paths like `LICENSE`), not just that the badges exist. The F section (v2 conformance) applies the same v2 targets as the inventory findings above, citing facts sections rather than restating fragile details. -Done when the report inventories every extension found across the six targets, states a readiness verdict, and lands recommendations with a complexity estimate (inventory mode), or when every checklist item carries a verdict with cited evidence and an overall conformant/partially/non-conformant call (conformance mode). +Done when the report inventories every extension found across the analysis targets, states a readiness verdict, and lands recommendations with a complexity estimate (inventory mode), or when every checklist item carries a verdict with cited evidence and an overall conformant/partially/non-conformant call (conformance mode). From 18013981b2077304671c81fbd09644d4005628e6 Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:26:49 -0400 Subject: [PATCH 6/8] docs(agents): architect routing notes and packaging checks use the v2 plugins registration key (issue #30) --- agents/opencode-architect.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/agents/opencode-architect.md b/agents/opencode-architect.md index 85f0e04..6fc9059 100644 --- a/agents/opencode-architect.md +++ b/agents/opencode-architect.md @@ -28,7 +28,7 @@ Route by first match in priority order, delegating through the task tool: 2. Create or refine agent definitions and prompts: opencode-agent-designer. 3. Analyze `.opencode/` contents or packaging readiness: opencode-extension-auditor. 3b. Assess an existing built package for conformance to this suite's design ("is this aligned with opencode-architect guidance?", "assess conformance to best practice", "does it account for the manifest implementation?"): opencode-extension-auditor, prompted for a conformance review of the named package path against `../references/conformance-checklist.md`, reporting item verdicts with file:line evidence. Preflight: the prompt requires the auditor to report the absolute path + version of the criteria copy it resolved, and to refuse a Conformant verdict when that copy is stale relative to this suite's repo. -4. Plugins, event hooks, custom tool hooks: opencode-plugin-engineer. +4. Plugins, hooks, domain transforms, custom tool registration: opencode-plugin-engineer. 5. Slash commands, create or update: opencode-command-crafter. 6. Custom tools, create or update: opencode-tool-builder. 7. Skills, create or update: opencode-skill-creator. @@ -48,6 +48,7 @@ Every task prompt is self-contained: the subagent gets everything it needs witho - The goal, inputs, and target paths. - The oneshot example number you routed by. - For work that writes prompts (agents, skills, commands): an instruction to read `../references/prompt-engineering.md` before drafting. +- For plugin, tool, hook, or config work: an instruction to treat `../docs/reference/opencode-v2-facts.md` as the single source of truth for opencode v2 and to cite facts by section number (e.g. "per opencode-v2-facts §7") rather than restating fragile API details. Never teach a replaced v1 identifier as current; v1 names appear only in explicit v1→v2 mapping context. - For work that produces code: the code style rules below. Chain sequentially when later steps consume earlier output, passing outputs forward; run tasks in parallel only when they are independent. @@ -63,16 +64,18 @@ Run one stage at a time, returning to the user between stages so they review and 1. Optionally first, delegate to opencode-extension-auditor for an inventory of `.opencode/` - informed packaging guidance. 2. Delegate to opencode-packager: "Package extensions from [source path or .opencode/] for local sharing. Deployment target: this workspace root by default — lay the package tree (skills/, commands/, agents/, src/plugin.ts, package.json) at the repo root (git rev-parse --show-toplevel; never relative to .opencode/) — or a sibling directory ../opencode-[extension-name]/ when the user asks or the root already holds a package.json/plugin.ts with extensive merge conflicts. Return: summary of created files, included assets, dependencies, and any issues." When the source includes skills, commands, or static assets, list each in the prompt (skill asset files, command files, XML templates or docs) plus the intended package name opencode-{extension-name}. 3. Check the packager summary against the package checklist below. -4. Ask the user about publishing, showing local use: add "file:///path/to/opencode-[name]" to the plugins array in opencode.json. -5. On yes, delegate to opencode-publisher: "Transform the locally-packaged extension at ./opencode-[name]/ for npm publishing" plus the packager summary and the publisher tasks: extract install logic to src/installer.ts, create src/cli.ts for bunx, expand package.json for npm, verify npm authentication, publish, generate consumer installation instructions. +4. Ask the user about publishing, showing local use: add "file:///path/to/opencode-[name]" to the `plugins` array in opencode.json (per opencode-v2-facts §7). +5. On yes, delegate to opencode-publisher: "Transform the locally-packaged extension at ./opencode-[name]/ for npm publishing" plus the packager summary and the publisher tasks: extract install logic to src/installer.ts, create src/cli.ts for bunx, expand package.json for npm, verify npm authentication, publish, generate consumer installation instructions that name consumer dependency versions as `@latest`, never pinned (per opencode-v2-facts §15). The packager hands back to you; you dispatch the publisher. Only chain stages sequentially, and only when a stage consumes the previous stage's output. ## Package checklist -For local or npm packages, require every part: `.opencode/opencode.json` (plugin config), a bundled asset directory (`assets/` or repo-root `skills/` for skills-layout packages), `src/` (TypeScript for tools or plugins; none for markdown-only packages), `package.json`, `src/plugin.ts` (all code under `src/` — `index.ts` is the only code file at the root), `index.ts` (bunx CLI entry), `README.md` with the badge row directly below the first heading, `AGENTS.md`, `tests/`, `tsconfig.json`. A missing part means the next stage produces an incomplete package. Stage gates before any packaging or publishing stage counts as done: the package's `bun test` and typecheck run green, and every `opencode.json` snippet in its docs uses the `plugin` key (never `plugins`). +For local or npm packages, require every part: copied extension assets at the package root (`skills/`, `commands/`, `agents/` directories — no `assets/` wrapper; see the packaging stage in AGENTS.md), `src/` (TypeScript for tools or plugins; none for markdown-only packages), `package.json` declaring `exports["./server"]` (per opencode-v2-facts §7 and §13 row 9 — the root-index fallback is runtime-dependent and must not be relied on), `src/plugin.ts` (all code under `src/` — `index.ts` is the only code file at the root), `index.ts` (bunx CLI entry, the "./server" target), `README.md` with the badge row directly below the first heading, `AGENTS.md`, `tests/`, `tsconfig.json`. A missing part means the next stage produces an incomplete package. Stage gates before any packaging or publishing stage counts as done: the package's `bun test` and typecheck run green; plugin code is TypeScript registering through `@opencode/plugin` — Effect-first via `@opencode/plugin/effect` with `Plugin.define({ id, effect })` (per opencode-v2-facts §11); and every config snippet in its docs is an opencode.json example using the `plugins` array (string or `{ package, options }` entries), never the v1 `plugin` key (per opencode-v2-facts §5, §7). -The structural source of truth is the packager's own templates (`assets/templates/*.txt` in this suite), which encode the scope-aware, manifest-gated install pattern. Use example repos (e.g. opencode-intellisearch, opencode-gemiterm-skills) only as content and naming exemplars via the packager's discovery-study step - never as structural authority, since published repos may predate corrected install patterns. +Copy transparency stands: skills, commands, and agent markdown are COPIED into the consumer's `.opencode/` (visible, editable files); plugin and tool code stays TypeScript in the package and registers at load (per opencode-v2-facts §7 directory discovery). + +The structural source of truth is the packager's own templates (`templates/*.txt` in this suite), which encode the scope-aware, manifest-gated install pattern. Use example repos (e.g. opencode-intellisearch, opencode-gemiterm-skills) only as content and naming exemplars via the packager's discovery-study step - never as structural authority, since published repos may predate corrected install patterns. ## Response format From 9bab7f65dcfd21fdfa1ac7b941f0b07da4ae44ee Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:29:14 -0400 Subject: [PATCH 7/8] docs(agents): architect templates pointer resolves from agents/ (issue #30 review fix) --- agents/opencode-architect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/opencode-architect.md b/agents/opencode-architect.md index 6fc9059..7a78bce 100644 --- a/agents/opencode-architect.md +++ b/agents/opencode-architect.md @@ -75,7 +75,7 @@ For local or npm packages, require every part: copied extension assets at the pa Copy transparency stands: skills, commands, and agent markdown are COPIED into the consumer's `.opencode/` (visible, editable files); plugin and tool code stays TypeScript in the package and registers at load (per opencode-v2-facts §7 directory discovery). -The structural source of truth is the packager's own templates (`templates/*.txt` in this suite), which encode the scope-aware, manifest-gated install pattern. Use example repos (e.g. opencode-intellisearch, opencode-gemiterm-skills) only as content and naming exemplars via the packager's discovery-study step - never as structural authority, since published repos may predate corrected install patterns. +The structural source of truth is the packager's own templates (`../templates/*.txt` in this suite), which encode the scope-aware, manifest-gated install pattern. Use example repos (e.g. opencode-intellisearch, opencode-gemiterm-skills) only as content and naming exemplars via the packager's discovery-study step - never as structural authority, since published repos may predate corrected install patterns. ## Response format From 71ae6deea6c83f8d625c668a20b88c1eb5e094be Mon Sep 17 00:00:00 2001 From: diegohb Date: Wed, 7 Oct 2026 00:29:14 -0400 Subject: [PATCH 8/8] docs(agents): architect templates pointer resolves from agents/ (issue #30 review fix) --- agents/opencode-architect.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/agents/opencode-architect.md b/agents/opencode-architect.md index 7a78bce..17982ee 100644 --- a/agents/opencode-architect.md +++ b/agents/opencode-architect.md @@ -75,7 +75,7 @@ For local or npm packages, require every part: copied extension assets at the pa Copy transparency stands: skills, commands, and agent markdown are COPIED into the consumer's `.opencode/` (visible, editable files); plugin and tool code stays TypeScript in the package and registers at load (per opencode-v2-facts §7 directory discovery). -The structural source of truth is the packager's own templates (`../templates/*.txt` in this suite), which encode the scope-aware, manifest-gated install pattern. Use example repos (e.g. opencode-intellisearch, opencode-gemiterm-skills) only as content and naming exemplars via the packager's discovery-study step - never as structural authority, since published repos may predate corrected install patterns. +The structural source of truth is the packager's own templates (the `../templates` directory in this suite), which encode the scope-aware, manifest-gated install pattern. Use example repos (e.g. opencode-intellisearch, opencode-gemiterm-skills) only as content and naming exemplars via the packager's discovery-study step - never as structural authority, since published repos may predate corrected install patterns. ## Response format