mirror of
https://github.com/EveryInc/compound-engineering-plugin.git
synced 2026-06-26 12:23:01 +02:00
refactor(opencode): align output with current permissions
Stop emitting deprecated tools config for OpenCode permission modes. Update the OpenCode schema notes and add a regression that the current CE plugin outputs skills plus subagents, not command files.
This commit is contained in:
+11
-5
@@ -26,10 +26,11 @@ https://opencode.ai/config.json
|
||||
## Core config keys
|
||||
|
||||
- `model` and `small_model` set the primary and lightweight models; `provider` configures provider options.
|
||||
- `tools` is still supported but deprecated; permissions are now the canonical control surface.
|
||||
- `tools` is still supported but deprecated as of OpenCode v1.1.1; permissions are now the canonical control surface.
|
||||
- `permission` controls tool approvals and can be configured globally or per tool, including pattern-based rules.
|
||||
- `mcp`, `instructions`, `disabled_providers`, `enabled_providers`, and `plugin` are supported config sections.
|
||||
- `plugin` can list npm packages to load at startup.
|
||||
- `skills.paths` and `skills.urls` can add extra skill discovery locations, but CE should not depend on them until the layout is smoke-tested locally with OpenCode.
|
||||
|
||||
## Tools
|
||||
|
||||
@@ -45,27 +46,31 @@ https://opencode.ai/config.json
|
||||
## Agents
|
||||
|
||||
- Agents can be configured in `opencode.json` or as markdown files in `~/.config/opencode/agents/` or `.opencode/agents/`.
|
||||
- Agent config supports `mode`, `model`, `temperature`, `tools`, and `permission`, and agent configs override global settings.
|
||||
- Agent config supports `mode`, `model`, `variant`, `temperature`, `top_p`, `hidden`, `steps`, `options`, `permission`, and other schema fields. `tools` still exists but is deprecated.
|
||||
- `mode` can be `primary`, `subagent`, or `all`; omitted mode defaults to `all`.
|
||||
- `hidden: true` hides subagents from the `@` autocomplete menu.
|
||||
- `permission.task` controls which subagents an agent may invoke.
|
||||
- Model IDs use the `provider/model-id` format.
|
||||
|
||||
## Skills
|
||||
|
||||
- Skills are reusable `SKILL.md` definitions loaded on demand through OpenCode's native `skill` tool.
|
||||
- OpenCode searches direct child skill directories only:
|
||||
- OpenCode searches direct child skill directories in its built-in roots:
|
||||
- `.opencode/skills/<name>/SKILL.md`
|
||||
- `~/.config/opencode/skills/<name>/SKILL.md`
|
||||
- `.claude/skills/<name>/SKILL.md`
|
||||
- `~/.claude/skills/<name>/SKILL.md`
|
||||
- `.agents/skills/<name>/SKILL.md`
|
||||
- `~/.agents/skills/<name>/SKILL.md`
|
||||
- The config schema also exposes `skills.paths` and `skills.urls` for extra skill sources. Do not switch CE to those until tested against a local OpenCode install; direct `~/.config/opencode/skills/<name>/SKILL.md` remains the stable writer shape.
|
||||
- Skill frontmatter recognizes `name`, `description`, `license`, `compatibility`, and `metadata`; unknown fields are ignored.
|
||||
- Skill names must be lowercase alphanumeric with single hyphen separators and must match the directory name.
|
||||
|
||||
## Commands
|
||||
|
||||
- Commands can be configured in `opencode.json` or as Markdown files in `~/.config/opencode/commands/` or `.opencode/commands/`.
|
||||
- Markdown command frontmatter can include fields such as `description`, `agent`, and `model`; the body becomes the prompt template.
|
||||
- Markdown command frontmatter can include fields such as `description`, `agent`, `model`, and `subtask`; the body becomes the prompt template.
|
||||
- If a command targets an agent whose mode is `subagent`, OpenCode invokes it as a subagent by default. `subtask: true` can force subagent invocation.
|
||||
|
||||
## Plugins and events
|
||||
|
||||
@@ -79,8 +84,9 @@ https://opencode.ai/config.json
|
||||
- The current CE writer shape is still appropriate in April 2026:
|
||||
- `~/.config/opencode/opencode.json`
|
||||
- `~/.config/opencode/agents/*.md`
|
||||
- `~/.config/opencode/commands/*.md`
|
||||
- `~/.config/opencode/commands/*.md` only when a source plugin ships commands
|
||||
- `~/.config/opencode/plugins/*.ts`
|
||||
- `~/.config/opencode/skills/*/SKILL.md`
|
||||
- OpenCode's plugin system is useful for JS/TS hooks and custom tools, but current docs do not describe a native marketplace command that consumes CE's `.claude-plugin/marketplace.json` and installs the full skills/agents/commands payload.
|
||||
- Keep the custom Bun writer until OpenCode documents a native distribution path for packaged skills and agents.
|
||||
- The `compound-engineering` plugin currently emits skills and subagent Markdown files for OpenCode. It should not emit deprecated `tools` config; permission config is enough for non-default permission modes.
|
||||
|
||||
@@ -362,11 +362,6 @@ function applyPermissions(
|
||||
}
|
||||
|
||||
const permission: Record<string, "allow" | "deny" | Record<string, "allow" | "deny">> = {}
|
||||
const tools: Record<string, boolean> = {}
|
||||
|
||||
for (const tool of sourceTools) {
|
||||
tools[tool] = mode === "broad" ? true : enabled.has(tool)
|
||||
}
|
||||
|
||||
if (mode === "broad") {
|
||||
for (const tool of sourceTools) {
|
||||
@@ -415,7 +410,6 @@ function applyPermissions(
|
||||
}
|
||||
|
||||
config.permission = permission
|
||||
config.tools = tools
|
||||
}
|
||||
|
||||
function normalizeTool(raw: string): string | null {
|
||||
|
||||
+20
-2
@@ -4,19 +4,37 @@ export type OpenCodeConfig = {
|
||||
$schema?: string
|
||||
model?: string
|
||||
default_agent?: string
|
||||
/** @deprecated OpenCode v1.1.1+ uses permission as the canonical control surface. */
|
||||
tools?: Record<string, boolean>
|
||||
permission?: Record<string, OpenCodePermission | Record<string, OpenCodePermission>>
|
||||
agent?: Record<string, OpenCodeAgentConfig>
|
||||
mcp?: Record<string, OpenCodeMcpServer>
|
||||
skills?: OpenCodeSkillsConfig
|
||||
}
|
||||
|
||||
export type OpenCodeAgentConfig = {
|
||||
description?: string
|
||||
mode?: "primary" | "subagent"
|
||||
mode?: "primary" | "subagent" | "all"
|
||||
model?: string
|
||||
variant?: string
|
||||
temperature?: number
|
||||
top_p?: number
|
||||
prompt?: string
|
||||
disable?: boolean
|
||||
hidden?: boolean
|
||||
color?: string
|
||||
steps?: number
|
||||
/** @deprecated Use steps instead. */
|
||||
maxSteps?: number
|
||||
options?: Record<string, unknown>
|
||||
/** @deprecated OpenCode v1.1.1+ uses permission as the canonical control surface. */
|
||||
tools?: Record<string, boolean>
|
||||
permission?: Record<string, OpenCodePermission>
|
||||
permission?: Record<string, OpenCodePermission | Record<string, OpenCodePermission>>
|
||||
}
|
||||
|
||||
export type OpenCodeSkillsConfig = {
|
||||
paths?: string[]
|
||||
urls?: string[]
|
||||
}
|
||||
|
||||
export type OpenCodeMcpServer = {
|
||||
|
||||
@@ -15,6 +15,24 @@ const compoundEngineeringRoot = path.join(
|
||||
)
|
||||
|
||||
describe("convertClaudeToOpenCode", () => {
|
||||
test("current compound-engineering output is skills and subagents, not commands", async () => {
|
||||
const plugin = await loadClaudePlugin(compoundEngineeringRoot)
|
||||
const bundle = convertClaudeToOpenCode(plugin, {
|
||||
agentMode: "subagent",
|
||||
inferTemperature: true,
|
||||
permissions: "none",
|
||||
})
|
||||
|
||||
expect(bundle.agents.length).toBeGreaterThan(0)
|
||||
expect(bundle.skillDirs.length).toBeGreaterThan(0)
|
||||
expect(bundle.commandFiles).toHaveLength(0)
|
||||
expect(bundle.plugins).toHaveLength(0)
|
||||
expect(bundle.config.tools).toBeUndefined()
|
||||
|
||||
const parsedAgents = bundle.agents.map((agent) => parseFrontmatter(agent.content))
|
||||
expect(parsedAgents.every((agent) => agent.data.mode === "subagent")).toBe(true)
|
||||
})
|
||||
|
||||
test("from-command mode: map allowedTools to global permission block", async () => {
|
||||
const plugin = await loadClaudePlugin(fixtureRoot)
|
||||
const bundle = convertClaudeToOpenCode(plugin, {
|
||||
@@ -24,6 +42,7 @@ describe("convertClaudeToOpenCode", () => {
|
||||
})
|
||||
|
||||
expect(bundle.config.command).toBeUndefined()
|
||||
expect(bundle.config.tools).toBeUndefined()
|
||||
expect(bundle.commandFiles.find((f) => f.name === "workflows:review")).toBeDefined()
|
||||
expect(bundle.commandFiles.find((f) => f.name === "plan_review")).toBeDefined()
|
||||
|
||||
@@ -275,6 +294,7 @@ describe("convertClaudeToOpenCode", () => {
|
||||
inferTemperature: false,
|
||||
permissions: "broad",
|
||||
})
|
||||
expect(broadBundle.config.tools).toBeUndefined()
|
||||
expect(broadBundle.config.permission).toEqual({
|
||||
read: "allow",
|
||||
write: "allow",
|
||||
|
||||
Reference in New Issue
Block a user