How the Compound CLI Resolves Plugin Paths from GitHub Repositories

The Compound CLI resolves plugin paths through a three-stage pipeline that first checks for local filesystem paths, then clones the repository from GitHub into a temporary directory, and finally validates the requested plugin exists within the plugins/ subdirectory.

When you execute compound-plugin install my-plugin, the CLI must translate a simple string identifier into a concrete filesystem location containing the Claude plugin source code. This resolution logic lives in the EveryInc/compound-engineering-plugin repository and handles both local development workflows and remote GitHub installations through a deterministic fallback strategy.

The Three-Stage Resolution Process

The entry point resolvePluginPath() in src/commands/install.ts orchestrates the entire resolution flow through three distinct stages.

Stage 1: Distinguishing Local vs. Remote Paths

First, the CLI determines whether your input refers to a local directory or a remote GitHub repository. The resolvePluginPath() function checks if the argument starts with ., /, or ~ (lines 41-49).

If detected as a local path, the CLI expands the tilde notation using expandHome() from src/utils/resolve-home.ts, then validates existence via pathExists() from src/utils/files.ts. Valid local paths return immediately without any network operations.

Stage 2: Fetching from GitHub

When the input is not a local path, the CLI invokes resolveGitHubPluginPath() (lines 93-115). This function creates a temporary directory and determines the source URL through resolveGitHubSource().

By default, the CLI clones from the main compound-engineering-plugin repository. However, you can override this via the COMPOUND_PLUGIN_GITHUB_SOURCE environment variable to use forks or private mirrors.

The cloneGitHubRepo() helper (lines 23-33) executes a shallow clone using git clone --depth 1 via Bun's spawn API. This minimizes bandwidth and storage by fetching only the latest commit.

Stage 3: Locating the Plugin Directory

After cloning, the CLI validates the repository structure. It expects plugins to reside under plugins/<plugin-name> within the cloned repository (lines 123-139).

If the directory exists, resolveGitHubPluginPath() returns an object containing:

  • path: The absolute path to the plugin directory
  • cleanup: An async function that removes the temporary clone directory

If the plugin directory is missing, the cleanup function executes immediately to delete the temporary files, and the CLI throws an error indicating the plugin was not found in the repository.

Key Helper Functions and Utilities

Several utility modules support the resolution pipeline:

Function Location Purpose
expandHome / resolveTargetHome src/utils/resolve-home.ts Expands ~ to the user's home directory for local path resolution
pathExists src/utils/files.ts Async wrapper around fs.access to safely verify filesystem existence
cloneGitHubRepo src/commands/install.ts (lines 23-33) Executes shallow git clones via Bun's spawn API

Practical Usage Examples

Install a plugin from the default GitHub repository:

compound-plugin install my-awesome-skill

Install a local plugin during development:

compound-plugin install ./my-local-plugin
compound-plugin install ~/projects/my-plugin

Use a forked or private repository:

COMPOUND_PLUGIN_GITHUB_SOURCE=https://github.com/YourOrg/compound-engineering-plugin \
  compound-plugin install my-awesome-skill

Programmatic usage of the resolution logic:

import { resolvePluginPath } from "./src/commands/install"

// Resolves "my-plugin" to a temporary GitHub clone
const result = await resolvePluginPath("my-plugin")

console.log(result.path)      // /tmp/compound-plugin-abc123/plugins/my-plugin
await result.cleanup?.()     // Removes the temporary directory

Summary

  • The CLI distinguishes local paths (starting with ., /, or ~) from remote GitHub identifiers before attempting any network operations.
  • Remote resolution clones the compound-engineering-plugin repository into a temporary directory using a shallow git clone for performance.
  • The CLI expects plugins to follow the plugins/<plugin-name> directory structure within the repository and returns a cleanup function to remove temporary files after installation.
  • Override the default GitHub source using the COMPOUND_PLUGIN_GITHUB_SOURCE environment variable for forks or private mirrors.

Frequently Asked Questions

How does the CLI handle local plugin paths versus GitHub repositories?

The CLI checks if the provided argument starts with ., /, or ~ to identify local filesystem paths. If detected, it expands the path using expandHome() and verifies existence with pathExists(). If the argument does not match local path patterns, the CLI treats it as a GitHub repository identifier and proceeds to clone the default or configured repository source.

Can I install plugins from a forked version of the repository?

Yes. Set the COMPOUND_PLUGIN_GITHUB_SOURCE environment variable to your fork's URL before running the install command. The resolveGitHubSource() function checks this environment variable first, allowing you to override the default EveryInc/compound-engineering-plugin repository with private mirrors or organizational forks.

What happens if the requested plugin does not exist in the repository?

If the CLI cannot find a directory matching plugins/<plugin-name> within the cloned repository, it immediately executes the cleanup function to delete the temporary clone directory and throws an error. This ensures no orphaned temporary files remain on your filesystem when requesting non-existent plugins.

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 →