Adapter Trade-offs: Inject Once or Transform Every Turn

The OpenCode integration shows why i-have-adhd cannot use one universal persistence mechanism. Its plugin must make the skill and command discoverable in a host where global and project-local installations expose different surfaces, then optionally keep the rules active by transforming the system prompt on every turn. This chapter compares that approach with startup injection and stateful context markers, so readers can choose an adapter strategy based on host capabilities rather than on a slogan about portability.

OpenCode has two discovery problems to solve

A skill can exist on disk and still be invisible to the user. The host may know where skills live but not display a command in its slash menu. Or a project-local installation may expose a command while a global installation, loaded from outside the project, does not. In either case, the reader experiences a response-style problem as a discoverability failure: there is no obvious way to invoke the policy.

The OpenCode plugin addresses this in two layers. It registers the repository’s skills directory so the native skill mechanism can find the canonical content. It also registers an i-have-adhd command when one is not already present. The command is built from a small Markdown file whose frontmatter is a JSON object containing metadata and whose body tells the host to use the skill for the session. JSON is valid YAML, so the plugin can parse the same metadata without adding a separate YAML dependency.

That command registration is not redundant with skill discovery. The repository’s tests document a global-install case in which the skill-sourced command was not surfaced in the terminal interface. The plugin needs to make the command available even when the project-local command directory is not involved. This is a good example of an adapter solving a host-specific boundary rather than changing the response policy.

The plugin is careful about existing configuration. During configuration, it adds the skills path only if it is not already present. It adds its command only if the host has not already defined one with that name. If a user or another layer has supplied an existing command, the plugin preserves that definition. If the command file is missing or malformed, the plugin leaves skill discovery intact instead of failing the whole configuration step.

These choices implement a general rule for integrations: add the minimum surface needed to make the feature usable, and treat the host’s existing configuration as owned by someone else. Overwriting a command or duplicating a path would be a side effect unrelated to response shaping. It would create the very kind of environmental friction the project is meant to reduce.

OpenCode’s optional always-on path takes a different route from the Pi/OMP extension. It checks for an OpenCode-specific opt-in flag. When that flag exists, it appends the ruleset to the system prompt on every turn. When the flag is absent, it leaves the prompt unchanged. The on-demand command remains available either way.

Appending on every turn is straightforward to reason about.