Opt-in output styles for OpenCode: system prompts injected alongside the base system, activated only via tuple config. Works on OpenCode 1.x and 2.x.
Styles are system prompts placed alongside the base system. A style injects a block of instructions, or undefined to inject nothing. Two entry points, same outcome: a hook for 1.x, an agent transform for 2.x.
Styles are opt-in: they apply only when activated by a tuple [name, { options }] in opencode.json / opencode.jsonc. Bare name or auto-load means the neutral default (no-op).
learning: active learning mode ("build and understand"). Requires user contribution on code decisions;★ Insightblocks; instructions in English.default: neutral. Injects nothing. Useful for installing the package without altering any session's behavior.
Drop a Markdown file into a styles/ directory and it becomes a style named after the file (without .md):
- Global:
~/.config/opencode/styles/*.md(respectsXDG_CONFIG_HOME) - Project:
{project}/.opencode/styles/*.md
Singular style/ is also supported for backwards compatibility with OpenCode's own convention. Precedence on name collision: built-in < global < project (a project file can override a built-in such as learning).
{
"plugin": [["opencode-output-styles", { "style": "my-style" }]]
}Escape hatch for a file anywhere on disk:
{
"plugin": [["opencode-output-styles", { "style": "./prompts/reviewer.md" }]]
}Absolute paths are used as-is; relative paths resolve against the current working directory. A missing file or unknown name throws with the list of available styles and searched directories.
Notes:
- Styles are Markdown text only (no code execution). Safe against broken or malicious files.
- Style files are cached by mtime: edits are picked up automatically without restarting OpenCode. An empty or unreadable style file logs a warning and injects nothing.
insightsis specific to the built-inlearningstyle; custom styles are static text.
style: the style to activate (a built-in name, a discovered name, or a path).insights: setfalseto drop the★ Insightblock from thelearningstyle.agent: which agent receives the style. An agent id (defaultbuild), orall. On OpenCode 1.x the hook cannot scope by agent, so the style reaches whichever agent is running.
Add the tuple to opencode.json (or opencode.jsonc) in your project, or to the global config ~/.config/opencode/opencode.jsonc:
{
"plugin": [["opencode-output-styles", { "style": "learning" }]]
}Runs on every LLM call of every session, including title generation of the first message. About 498 tokens per call. Consider before enabling on long or high-volume sessions.
Remove the tuple from opencode.json / opencode.jsonc. To remove the package: npm uninstall opencode-output-styles.
- Supports OpenCode 1.x and 2.x (hook on 1.x, agent transform on 2.x). Minimum
engines.opencode >=1.18.0. Tested with 1.18.35 (1.x) and 2.2.5 (2.x). - On OpenCode 2.x the project directory is taken from
process.cwd()(the v2 plugin context exposes no directory). Opening a project from a different working directory may resolve project styles against the wrong root. - The plugin cannot distinguish title calls from build calls: instructions reach the title model on the first message of every session.
input.modeldoes not reliably expose the model identifier at runtime; no model-based filtering.
Ports behaviors from Claude Code's Learning Output Style Plugin and Explanatory Output Style Plugin into OpenCode as an opt-in style manager. The learning style was the first implementation; its instruction text was reimplemented from scratch (clean-room), no literal copying, attribution by link. MIT License.
User: any request
Plugin: injects nothing; OpenCode behaves as usual.
User: "Implement a retry function with backoff in TypeScript"
Plugin: scaffolds RetryOptions + retry<T>(...), inserts // TODO: backoff policy, outlines 2-3 approaches with trade-offs, then stops. Never reveals the solution; waits for you to write it.
User: "Create the package.json for the project"
Plugin: implements directly, no contribution requested.
User: "How do you decide between LRU and TTL cache here?"
Plugin: ★ Insight block with codebase-specific points (e.g. lazy TTLCache scan, cache.ts:9, Map.get O(1)), not generic concepts.
Contributions are welcome. See CONTRIBUTING.md for setup, the commit convention and the PR flow. By participating, you agree to the Code of Conduct.
Report vulnerabilities privately via GitHub Security Advisories. See SECURITY.md for the support policy.