How the `--permissions` Flag Works in Compound-Plugin Conversion

The --permissions flag controls how tool access rights are generated during compound-plugin conversion, offering three modes: none (no permissions), broad (allow all tools), or from-commands (inherit from Claude command definitions).

When converting Claude Desktop plugins to OpenCode and other target formats using the EveryInc/compound-engineering-plugin repository, the --permissions flag determines whether the generated plugin is permissive, restrictive, or inherits fine-grained tool allowances defined in the original Claude commands.

Understanding the --permissions Flag in Compound-Plugin Conversion

The --permissions flag configures OpenCode permission settings (and equivalent settings for other target formats that reuse the same conversion logic). According to the source code in src/converters/claude-to-opencode.ts, the flag accepts one of three string values defined by the PermissionMode type:

  • "none" – Generates no permission entries
  • "broad" – Grants blanket access to all available tools
  • "from-commands" – Extracts specific tool permissions from each Claude command's allowedTools declarations

How the --permissions Flag Is Parsed and Validated

The flag processing begins in src/commands/convert.ts, where the CLI argument is validated against a strict allowlist:

const permissionModes: PermissionMode[] = ["none", "broad", "from-commands"];

const permissions = String(args.permissions);
if (!permissionModes.includes(permissions as PermissionMode)) {
  throw new Error(`Unknown permissions mode: ${permissions}`);
}

const options = {
  // …
  permissions: permissions as PermissionMode, // Passed to all converters
};

This validation ensures that only supported permission modes reach the conversion logic. The options object containing the validated permissions value is then forwarded to every target converter (OpenCode, Codex, Droid, Cursor, Pi, and Gemini).

Three Permission Modes Explained

Inside src/converters/claude-to-opencode.ts, the applyPermissions function implements the logic for each mode. The function receives the OpenCode configuration object, the array of Claude commands, and the selected PermissionMode.

none Mode

When mode === "none", the function returns immediately without modifying the configuration:

if (mode === "none") return; // No permission entries added

This produces an OpenCode plugin with no permission or tools sections, effectively requiring users to manually configure access rights after installation.

broad Mode

When mode === "broad", the converter enables every tool in the sourceTools array (which includes "read", "write", "edit", "bash", and others):

if (mode === "broad") {
  enabled = new Set(sourceTools);
}

// Later in the function:
for (const tool of sourceTools) {
  tools[tool] = true;           // All tools enabled
  permission[tool] = "allow";   // All permissions set to "allow"
}

This generates a permissive plugin where all tools are allowed by default, suitable for internal or trusted environments.

from-commands Mode

The most granular mode, from-commands, parses the allowedTools property from each Claude command definition:

// Collect allowedTools from each command
for (const command of commands) {
  if (!command.allowedTools) continue;
  for (const tool of command.allowedTools) {
    const parsed = parseToolSpec(tool);
    if (!parsed.tool) continue;
    enabled.add(parsed.tool);
    if (parsed.pattern) {
      const normalizedPattern = normalizePattern(parsed.tool, parsed.pattern);
      if (!patterns[parsed.tool]) patterns[parsed.tool] = new Set();
      patterns[parsed.tool].add(normalizedPattern);
    }
  }
}

This mode supports fine-grained pattern matching. For example, a Claude command might specify write:src/**/*.md, which the converter translates into a permission object like:

{
  "write": {
    "*": "deny",
    "src/**/*.md": "allow"
  }
}

The from-commands mode ensures the converted plugin respects the original security boundaries defined by the plugin author.

Code Examples for Using --permissions

CLI Usage Examples

Convert a plugin with different permission modes:


# Default behavior (broad permissions)

bunx @every-env/compound-plugin convert ./plugins/compound-engineering --to opencode

# Restrictive mode - no tools allowed

bunx @every-env/compound-plugin convert ./plugins/compound-engineering --to opencode --permissions none

# Inherit permissions from Claude command definitions

bunx @every-env/compound-plugin convert ./plugins/compound-engineering --to opencode --permissions from-commands

Internal Implementation Details

The validation logic in src/commands/convert.ts ensures type safety:

const permissionModes: PermissionMode[] = ["none", "broad", "from-commands"];

const permissions = String(args.permissions);
if (!permissionModes.includes(permissions as PermissionMode)) {
  throw new Error(`Unknown permissions mode: ${permissions}`);
}

The applyPermissions helper in src/converters/claude-to-opencode.ts handles the three modes:

function applyPermissions(
  config: OpenCodeConfig,
  commands: ClaudeCommand[],
  mode: PermissionMode,
) {
  if (mode === "none") return;
  
  const sourceTools = ["read", "write", "edit", "bash"];
  const enabled = new Set<string>();
  const patterns: Record<string, Set<string>> = {};
  
  if (mode === "broad") {
    sourceTools.forEach(t => enabled.add(t));
  } else {
    // from-commands logic
    commands.forEach(cmd => {
      cmd.allowedTools?.forEach(tool => {
        const parsed = parseToolSpec(tool);
        if (parsed.tool) enabled.add(parsed.tool);
        if (parsed.pattern) {
          patterns[parsed.tool] = patterns[parsed.tool] || new Set();
          patterns[parsed.tool].add(normalizePattern(parsed.tool, parsed.pattern));
        }
      });
    });
  }
  
  // Build final config...
}

Summary

  • The --permissions flag in compound-plugin conversion controls how tool access rights are generated for OpenCode and other target formats.
  • Three modes are available: none (no permissions), broad (allow all tools), and from-commands (inherit from Claude command definitions).
  • The flag is validated in src/commands/convert.ts and processed by the applyPermissions helper in src/converters/claude-to-opencode.ts.
  • from-commands mode supports fine-grained pattern matching (e.g., write:src/**/*.md) for security-sensitive conversions.
  • All target converters (Codex, Droid, Cursor, Pi, Gemini) reuse the OpenCode permission logic for consistency.

Frequently Asked Questions

What is the default value for the --permissions flag in compound-plugin conversion?

If you omit the --permissions flag, the converter defaults to broad mode. This means the generated OpenCode plugin will have all tools enabled ("allow") and the tools map set to true for every available tool, creating a permissive configuration suitable for trusted environments.

How does the from-commands permission mode handle tool patterns?

The from-commands mode parses tool specifications that include path patterns (e.g., write:src/**/*.md or read:docs/**). When the applyPermissions function in src/converters/claude-to-opencode.ts encounters these patterns, it normalizes them and constructs a fine-grained permission object where specific paths can be allowed while others are denied, preserving the security boundaries defined in the original Claude plugin.

Can I use the --permissions flag when converting to formats other than OpenCode?

Yes. While the permission logic is implemented in src/converters/claude-to-opencode.ts, other target converters—including those for Codex, Droid, Cursor, Pi, and Gemini—delegate to the same applyPermissions helper or reuse the OpenCode conversion as an intermediate step. This ensures that the --permissions flag behaves consistently across all output formats, generating the appropriate access controls for each target platform.

What happens if I provide an invalid value to the --permissions flag?

The converter validates the flag value in src/commands/convert.ts against the permissionModes array, which only accepts "none", "broad", or "from-commands". If you provide any other value, the CLI throws an error with the message Unknown permissions mode: ${permissions} and halts execution, preventing invalid configurations from reaching the conversion logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →