Official
opencode-v2
OpenCode 2 agent provider: runs opencode serve (2.x) and talks to its /api over HTTP and server-sent events.
The app opens the listing; nothing installs until an agent in your Plugins workspace has read the files and you enable the plugin. In a terminal: cvg install convergence/opencode-v2@0.1.0
Permissions in 0.1.0
Files
permission.ts2.7 KB
// The session permission ruleset Convergence pushes for a chat. OpenCode
// decides a request against the agent's rules followed by the session's,
// and the last matching rule wins, so the session's rules settle what the
// composer's permission mode promises.
import type { PermissionRequest } from "./api.ts";
import { permissionMode } from "../sdk/agent.ts";
export interface Rule {
action: string;
resource: string;
effect: "allow" | "ask" | "deny";
}
const rule = (action: string, resource: string, effect: Rule["effect"]): Rule => ({ action, resource, effect });
/// The ruleset for a shared permission mode. Order matters: a narrow rule
/// only wins when it comes after the broad one it refines.
///
/// Auto is read as Supervised: OpenCode has no approval reviewer, so the
/// honest reading of "approve routine actions" is to keep asking.
export function ruleset(mode: string): Rule[] {
// Reads outside the workspace are an action of their own that the
// wildcard does not cover.
if (mode === permissionMode.FULL) return [rule("*", "*", "allow"), rule("external_directory", "*", "allow")];
const edits = mode === permissionMode.AUTO_EDITS ? "allow" : "ask";
return [
rule("*", "*", "ask"),
rule("read", "*", "allow"),
// OpenCode asks before reading environment files whatever the agent
// allows; a blanket read rule must not quietly remove that.
rule("read", "*.env", "ask"),
rule("read", "*.env.*", "ask"),
rule("read", "*.env.example", "allow"),
rule("glob", "*", "allow"),
rule("grep", "*", "allow"),
rule("list", "*", "allow"),
rule("lsp", "*", "allow"),
rule("skill", "*", "allow"),
rule("todowrite", "*", "allow"),
// Starting a subagent is not an action on the machine; its own tools
// ask under the same rules.
rule("subagent", "*", "allow"),
// The question tool only asks the user something; asking to ask is noise.
rule("question", "*", "allow"),
rule("edit", "*", edits),
rule("external_directory", "*", "ask"),
];
}
/// Whether the mode answers permission requests without the user. The
/// ruleset alone is not enough: a subagent session can carry rules of its
/// own.
export const repliesAutomatically = (mode: string) => mode === permissionMode.FULL;
/// The title of an approval card: the action and what it touches.
export function approvalTitle(request: PermissionRequest): string {
if (request.message) return request.message;
const action = request.action === "shell" ? "Run" : request.action[0]?.toUpperCase() + request.action.slice(1);
const resources = request.resources.filter(Boolean);
return resources.length ? `${action} ${resources.join(", ")}` : action;
}Versions
| Version | Published | Plugin API | Size | Permissions | Status |
|---|---|---|---|---|---|
| 0.1.0latest | Oct 5, 2026 | >=2 <3 | 45.1 KB | 4 permissions | Listed |
No comments yet.