Wayfinder map: fastCRW websearch plugin for opencode v2 #1

Closed
opened 2026-10-03 13:43:49 +00:00 by haylan · 1 comment
Owner

Destination

A build-ready spec for a custom opencode v2 plugin that replaces opencode's built-in websearch with a self-hosted fastCRW search backend (POST {baseURL}/v1/search). The spec fixes the verified plugin API shape, config surface (endpoint + token), packaging/distribution, and the repo build steps. The build itself is handed off afterwards.

Notes

  • Domain: opencode v2 plugin (https://opencode.ai/v2/docs/plugins), fastCRW self-hosted search API, TypeScript, npm, Gitea (git.arthurerlich.de via tea).
  • Chosen approach: a native websearch-provider plugin, NOT the official crw-mcp MCP server.
  • Config surface (decided): endpoint (baseURL) and token (apiKey) as plugin options, with env vars (CRW_API_URL / CRW_API_KEY) as fallback. The token must never be required in opencode.json.
  • The sample code supplied by the user (@opencode/plugin, Plugin.define, ctx.websearch.transform, plugins[].package/options) is a sketch, unverified against the real v2 docs. Facts come from the research ticket.
  • Setup items (npm init, Prettier, main branch protection via tea) are build steps that go into the spec, not map tickets. Only setup that unblocks a decision (installing skills) is a task ticket.
  • Consult skills: /grilling, /domain-modeling, /research, gitea-tea.
  • Tracker convention (no native parent/child in tea): each ticket's body starts with Map: #<map>; blocking uses Gitea's native issue dependencies.

Decisions so far

  • Research: verified opencode v2 plugin API — sketch is essentially right (Plugin.define needs a required id; plural plugins key; options via ctx.options; editor.add + editor.default.set(id)); TS types, time shape and provider-vs-default precedence unverified, check at runtime. Detail: docs/research/opencode-v2-plugin-api.md.
  • Research: fastCRW /v1/search API contract — POST {CRW_API_URL}/v1/search, optional Bearer CRW_API_KEY, query required, limit 1..20; data may be a flat array OR data.results (parse both); errors {success:false,error,error_code}; self-hosted search needs a SearXNG-style backend (else 503 search_disabled). Not tested against a live instance. Detail: docs/research/fastcrw-search-api.md.
  • Task: install opencode v2 and TypeScript skills — nothing to install: no opencode or TypeScript skill exists on skills.sh; existing skills (tdd, codebase-design, conventional-commits, gitea-tea) suffice, and docs/research/opencode-v2-plugin-api.md is the opencode reference.
  • Grilling: config surface for endpoint and token — options baseURL/apiKey/limit(8, clamp 1..20)/lang/tbs, env CRW_API_URL/CRW_API_KEY, default http://localhost:3000, token optional, setup throws on bad values, provider id fastcrw as the only default provider; three runtime checks listed in the ticket. Glossary: CONTEXT.md.
  • Grilling: packaging and distribution — Gitea npm registry, @haylan/opencode-fastcrw, plugin id fastcrw.websearch, tsc to dist/ (ESM), dev version in package.json; manual workflow_dispatch Action publishes the latest CHANGELOG.md version via a script against the registry API (no npm publish, skip if exists); main already protected. Runtime risk: scope-mapped install by name.
  • Grilling: result mapping and error semantics — parse data[] or data.results, map to {url,title,content,time:{}}, empty → [], throw fastCRW <status> <error_code>: <error> with hints for 401/503, abort untouched, fixed 30 s timeout, no retries, 429 status kept visible.
  • Grilling: test strategy, runtime checks and CI — node --test with mocked fetch over src/{config,search,index}.ts; four manual runtime checks and a manual npm run smoke recorded in docs/runtime-checks.md; .gitea/workflows/check.yml on PRs (ubuntu-latest, Node 24) becomes a required check on main; no pre-commit hooks.

Not yet specified

Out of scope

  • The crw-mcp MCP-server approach (mcp.servers.crw, websearch: false) — explicitly rejected in favour of a native plugin.
## Destination A **build-ready spec** for a custom opencode v2 plugin that replaces opencode's built-in websearch with a self-hosted fastCRW search backend (`POST {baseURL}/v1/search`). The spec fixes the verified plugin API shape, config surface (endpoint + token), packaging/distribution, and the repo build steps. The build itself is handed off afterwards. ## Notes - Domain: opencode v2 plugin (https://opencode.ai/v2/docs/plugins), fastCRW self-hosted search API, TypeScript, npm, Gitea (git.arthurerlich.de via `tea`). - Chosen approach: a **native websearch-provider plugin**, NOT the official `crw-mcp` MCP server. - Config surface (decided): endpoint (`baseURL`) and token (`apiKey`) as plugin options, with env vars (`CRW_API_URL` / `CRW_API_KEY`) as fallback. The token must never be required in `opencode.json`. - The sample code supplied by the user (`@opencode/plugin`, `Plugin.define`, `ctx.websearch.transform`, `plugins[].package/options`) is a **sketch, unverified** against the real v2 docs. Facts come from the research ticket. - Setup items (npm init, Prettier, main branch protection via `tea`) are build steps that go into the spec, not map tickets. Only setup that unblocks a decision (installing skills) is a task ticket. - Consult skills: `/grilling`, `/domain-modeling`, `/research`, `gitea-tea`. - Tracker convention (no native parent/child in `tea`): each ticket's body starts with `Map: #<map>`; blocking uses Gitea's native issue dependencies. ## Decisions so far - [Research: verified opencode v2 plugin API](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/2) — sketch is essentially right (`Plugin.define` needs a required `id`; plural `plugins` key; options via `ctx.options`; `editor.add` + `editor.default.set(id)`); TS types, `time` shape and provider-vs-default precedence unverified, check at runtime. Detail: `docs/research/opencode-v2-plugin-api.md`. - [Research: fastCRW /v1/search API contract](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/3) — `POST {CRW_API_URL}/v1/search`, optional Bearer `CRW_API_KEY`, `query` required, `limit` 1..20; `data` may be a flat array OR `data.results` (parse both); errors `{success:false,error,error_code}`; self-hosted search needs a SearXNG-style backend (else 503 `search_disabled`). Not tested against a live instance. Detail: `docs/research/fastcrw-search-api.md`. - [Task: install opencode v2 and TypeScript skills](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/4) — nothing to install: no opencode or TypeScript skill exists on skills.sh; existing skills (tdd, codebase-design, conventional-commits, gitea-tea) suffice, and `docs/research/opencode-v2-plugin-api.md` is the opencode reference. - [Grilling: config surface for endpoint and token](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/5) — options `baseURL`/`apiKey`/`limit`(8, clamp 1..20)/`lang`/`tbs`, env `CRW_API_URL`/`CRW_API_KEY`, default `http://localhost:3000`, token optional, `setup` throws on bad values, provider id `fastcrw` as the only default provider; three runtime checks listed in the ticket. Glossary: `CONTEXT.md`. - [Grilling: packaging and distribution](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/6) — Gitea npm registry, `@haylan/opencode-fastcrw`, plugin id `fastcrw.websearch`, tsc to `dist/` (ESM), dev version in `package.json`; manual `workflow_dispatch` Action publishes the latest `CHANGELOG.md` version via a script against the registry API (no `npm publish`, skip if exists); `main` already protected. Runtime risk: scope-mapped install by name. - [Grilling: result mapping and error semantics](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/7) — parse `data[]` or `data.results`, map to `{url,title,content,time:{}}`, empty → `[]`, throw `fastCRW <status> <error_code>: <error>` with hints for 401/503, abort untouched, fixed 30 s timeout, no retries, 429 status kept visible. - [Grilling: test strategy, runtime checks and CI](https://git.arthurerlich.de/haylan/fastcrw-opencode-websarch/issues/8) — `node --test` with mocked `fetch` over `src/{config,search,index}.ts`; four manual runtime checks and a manual `npm run smoke` recorded in `docs/runtime-checks.md`; `.gitea/workflows/check.yml` on PRs (`ubuntu-latest`, Node 24) becomes a required check on `main`; no pre-commit hooks. ## Not yet specified <!-- nothing left: all remaining fog graduated to tickets --> ## Out of scope - The `crw-mcp` MCP-server approach (`mcp.servers.crw`, `websearch: false`) — explicitly rejected in favour of a native plugin.
haylan added the wayfinder:map label 2026-10-03 13:43:49 +00:00
Author
Owner

Map complete. The destination, a build-ready spec, was reached and then built: the spec is docs/spec.md, the plugin is released as @haylan/opencode-fastcrw 0.0.1 (tag v0.0.1, package linked to this repository), and the runtime checks are recorded in docs/runtime-checks.md. All eight decision tickets were closed and nothing was left in the fog.

Map complete. The destination, a build-ready spec, was reached and then built: the spec is `docs/spec.md`, the plugin is released as `@haylan/opencode-fastcrw` 0.0.1 (tag `v0.0.1`, package linked to this repository), and the runtime checks are recorded in `docs/runtime-checks.md`. All eight decision tickets were closed and nothing was left in the fog.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: haylan/fastcrw-opencode-websearch#1