How to Debug Conversion Failures in the Compound Engineering Plugin

Run the CLI with explicit output flags and inspect console warnings to identify whether the failure occurs during target selection, conversion logic, or file writing.

The Compound Engineering Plugin from EveryInc provides a robust pipeline for transforming Claude plugins into alternative formats like OpenCode and Codex. When you need to debug conversion failures, understanding the four-stage architecture and common failure points in the source code will help you isolate issues systematically.

Understanding the Conversion Pipeline

The conversion process follows a strict sequence defined in src/commands/convert.ts. Each stage passes data to the next, and failures typically manifest at specific handoff points.

Step 1: Parse the Claude Plugin

The loadClaudePlugin function in src/parsers/claude.ts ingests the source plugin and validates its structure. If the input JSON is malformed or missing required fields, the pipeline exits here.

Step 2: Select the Target

The targets registry in src/targets/index.ts maps target names (e.g., opencode, codex) to their respective conversion functions and writers. This registry determines which converter logic executes based on the --to flag.

Step 3: Run the Converter

Each target invokes a specific converter, such as convertClaudeToOpenCode in src/converters/claude-to-opencode.ts. This stage handles model normalization, permission mapping, and hook conversion. If the converter returns null, the pipeline aborts before writing.

Step 4: Write the Bundle

The writer (e.g., writeOpenCodeBundle in src/targets/opencode.ts) persists the generated files to disk. Failures here typically involve file system permissions or path resolution errors in resolveTargetOutputRoot.

Common Conversion Failure Points

Conversion failures cluster around four specific error conditions in src/commands/convert.ts:

Step Symptom Location
Target registration Unknown target: … src/commands/convert.ts (lines 64‑68)
Target implementation Target … is registered but not implemented yet. src/commands/convert.ts (lines 70‑72)
Converter returns null Target … did not return a bundle. src/commands/convert.ts (lines 91‑94)
Writer throws File system stack trace Writer modules in src/targets/

Follow this systematic approach to debug conversion failures in the Compound Engineering Plugin:

  1. Run the CLI with explicit output and extra targets

    Execute the conversion with verbose flags to capture the full execution context:

    bun run src/cli.ts convert path/to/plugin --to opencode --output ./debug-out --also codex

    The CLI prints the converted directory and any warnings about unsupported tools or unmapped hook events.

  2. Check console warnings

    The converters use console.warn for non‑fatal issues. In convertClaudeToOpenCode, look for warnings around line 262 regarding missing model aliases, or around line 60 for hook‑mapping gaps. These warnings explain why generated bundles might be incomplete.

  3. Inspect the generated bundle

    Before the writer executes, the command holds the bundle in the bundle variable (see src/commands/convert.ts lines 90‑96). Temporarily add debug logging after line 92:

    console.log('DEBUG bundle keys:', Object.keys(bundle))

    This reveals the top‑level structure (config, agents, plugins, skillDirs) and confirms whether the converter produced valid output.

  4. Run the unit tests for the failing target

    The repository includes comprehensive tests. For OpenCode conversion failures, execute:

    bun test tests/converter.test.ts

    This test file validates command mapping, permissions, model normalization, hook conversion, and MCP server handling. A failing assertion pinpoints the exact conversion logic that is broken.

  5. Enable source‑level debugging

    Use Bun’s inspector to step through the conversion:

    bun run --inspect src/cli.ts convert path/to/plugin --to opencode

    Attach VS Code or Chrome DevTools to step into:

    • The target’s convert function (e.g., convertClaudeToOpenCode)
    • applyPermissions logic (lines 294‑360) for permission‑related failures
    • normalizeModel (lines 260‑275) for unexpected model IDs
  6. Validate the writer’s path resolution

    The writer modules compute output paths using resolveTargetOutputRoot in src/commands/convert.ts (lines 143‑149). Ensure that the resolved directory exists and that the process has write permissions.

  7. Re‑run with a minimal fixture

    Isolate plugin‑specific issues by converting the sample fixture:

    bun run src/cli.ts convert tests/fixtures/sample-plugin --to opencode

    If this succeeds, the failure stems from the source plugin’s structure rather than the conversion engine.

  8. Check for null bundle returns

    If you encounter Target … did not return a bundle, the converter returned null. This occurs when all commands are disabled (see early returns in convertCommands such as if (command.disableModelInvocation) continue). Verify that your source plugin contains enabled commands.

Adding Debug Logging to the Conversion Command

For persistent issues, instrument src/commands/convert.ts to expose intermediate state:

// Inside src/commands/convert.ts after the primary bundle is produced
if (!bundle) {
  throw new Error(`Target ${targetName} did not return a bundle.`)
}
console.log('DEBUG bundle keys:', Object.keys(bundle))
await target.write(primaryOutputRoot, bundle)

This prints the top‑level keys so you can verify that a non‑empty bundle was produced before the writer touches the filesystem.

Key Files for Debugging Conversion Failures

File Role
src/commands/convert.ts CLI entry point that selects the target, runs the converter, and writes the bundle
src/targets/index.ts Registry of all conversion targets and their implementation flags
src/converters/claude-to-opencode.ts Main OpenCode converter; contains model normalization, temperature inference, and permission handling
src/converters/claude-to-codex.ts Target‑specific conversion logic for Codex
src/targets/opencode.ts Writer that persists generated files for OpenCode
src/targets/codex.ts Writer that persists generated files for Codex
src/utils/resolve-home.ts Resolves ~ in user‑provided paths (used for --codex-home, --pi-home)
src/utils/files.ts Helpers for file‑system operations (ensureDir, writeJson, etc.)
tests/converter.test.ts Unit test that validates the OpenCode conversion pipeline; a quick sanity check for debugging

Summary

  • The conversion pipeline in EveryInc/compound-engineering-plugin consists of four stages: parsing, target selection, conversion, and writing.
  • Most failures occur at specific handoff points in src/commands/convert.ts, identifiable by error messages like Unknown target or did not return a bundle.
  • To debug conversion failures, run the CLI with explicit flags, check console.warn output for non‑fatal issues, inspect the bundle structure before writing, and run target‑specific unit tests.
  • Enable source‑level debugging with bun run --inspect to step through converters like convertClaudeToOpenCode and verify logic in applyPermissions or normalizeModel.
  • Use the sample fixture at tests/fixtures/sample-plugin to isolate plugin‑specific issues from engine bugs.

Frequently Asked Questions

Why does the conversion fail with "Unknown target"?

This error originates in src/commands/convert.ts (lines 64‑68) when the target name provided via --to does not exist in the targets registry exported from src/targets/index.ts. Verify that you are using a supported target name such as opencode or codex, and check that the target is properly registered in the index file.

What does "Target did not return a bundle" mean?

This message appears in src/commands/convert.ts (lines 91‑94) when the converter function returns null instead of a bundle object. This typically happens when all commands in the source plugin are disabled (e.g., command.disableModelInvocation is true) or when the converter encounters an early return condition. Check the source plugin for enabled commands and review the converter logic for early exits.

How can I see the intermediate bundle before it is written to disk?

Insert a temporary debug log in src/commands/convert.ts immediately after the bundle is generated (around line 92). Add console.log(JSON.stringify(bundle, null, 2)) to print the full bundle structure, or use console.log('DEBUG bundle keys:', Object.keys(bundle)) to verify the top‑level keys (config, agents, plugins, skillDirs). Remove the log after debugging to avoid cluttering production output.

Which test file should I run to verify the OpenCode converter?

Run bun test tests/converter.test.ts to execute the unit tests for the OpenCode conversion pipeline. This test file validates command mapping, permissions, model normalization, hook conversion, and MCP server handling. If a specific conversion feature is failing, the test output will point to the exact assertion that failed, helping you locate the bug in src/converters/claude-to-opencode.ts or related modules.

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 →