Documentation Index
Fetch the complete documentation index at: https://docs.runlayer.com/llms.txt
Use this file to discover all available pages before exploring further.
What is a Plugin?
A Plugin is a curated bundle of tools from one or more MCP servers (“connectors”). It gives you a single MCP endpoint you can add to your AI client, while still enforcing all the underlying Runlayer policies and access controls.
Plugins are useful when you want:
- A purpose-built toolset for a workflow (e.g. “Release Management”, “Customer Support”, “On-call”)
- One connection in your MCP client instead of many
- A safe, shareable setup (private to you or public within your workspace)
Plugins expose tools and prompts (no resources). Skill files attached to a
plugin are available as MCP prompts that your AI client can request by name.
Creating a Plugin
Open Plugins
Navigate to Plugins in the sidebar.
Create a new Plugin
Click Create new and provide a name, optional description, and optional namespace.A namespace (e.g. acme/review) groups related Plugins and ensures a unique (namespace, path) pair. It is optional — leave it blank for one-off Plugins.
Choose privacy
- Private: only you can access it
- Public: anyone in your workspace can access it
Add connectors and pick tools
Select the MCP servers you want, then choose which tools from each server should be included in the Plugin.
Using a Plugin in an MCP client
Open the Plugin and click Add to Client. Runlayer will generate the correct connection details for your selected client.
Deploy an Agent from a Plugin
From any Plugin detail page, click Deploy as Agent to create a new Agent that automatically inherits the plugin’s connectors and skills. This is the fastest path from a curated toolset to a running agent.
- Add connectors: open a Plugin and click Add Connectors
- Remove connectors: open the connector menu and choose Remove connector
- Review tools: expand a connector to see the tools included in the Plugin
Dynamic tools are an optimization for Plugins with many tools.
How it works
When Dynamic tools is enabled, the Plugin does not expose every underlying tool definition directly. Instead, it exposes two meta-tools:
search_tools: search for the most relevant tools by describing what you want to do (returns tool names + descriptions + input schemas)
execute_tool: execute a specific tool by name with arguments (typically chosen from search_tools results)
This creates a two-step flow: search → execute.
Why it’s useful
Sending hundreds of tool definitions (names, descriptions, and JSON schemas) to the LLM can push requests onto a “context route” that:
- Degrades model performance (more noise in the prompt)
- Increases latency (more tokens processed)
- Increases cost (larger prompts and tool schemas)
Dynamic tools keeps the prompt/tooling surface small until the model actually needs a specific tool.
When to use it
- Enable Dynamic tools for Plugins with many connectors/tools, or when tool schemas are large.
- Disable it for small Plugins where you want the model to see all tools immediately without an extra search step.
When a Plugin has linked skills, those skills are automatically exposed as read-only tools alongside the connector tools. The exposure strategy depends on how many skills the Plugin has:
Fewer than 25 skills — one tool per skill, named get_<skill_slug>. The tool returns all files for that skill. An optional file argument lets the caller read a single file by title.
25 or more skills — two shared search tools replace the per-skill tools:
| Tool | Description |
|---|
getSkill | Full-text search across skill names, descriptions, and file content. Returns up to 5 ranked matches with their file lists. |
getSkillFile | Reads one file by exact skill name and file title (use values returned by getSkill). |
This keeps the tool surface small for Plugins with large skill libraries while still giving the model access to every skill through search.
Authoring and syncing with CLI
Runlayer can also publish Claude-format plugins from disk with uvx runlayer plugins push.
Directory structure
my-plugin/
.claude-plugin/
plugin.json
.mcp.json
skills/
ticket-triage/
SKILL.md
helper.py
code-review/
SKILL.md
prompts.md
commands/
review.md
agents/
code-reviewer.md
hooks/
hooks.json
validate.sh
scripts/
deploy.sh
Manifest
Runlayer uses .claude-plugin/plugin.json as the plugin manifest and now reads mcpServers from two places: inline in the manifest (preferred) or as a legacy .mcp.json.
{
"name": "my-plugin",
"version": "1.0.0",
"description": "Review and triage code"
}
| Field | Required | Notes |
|---|
name | Yes | Used as the plugin display name |
version | No | Stored for discovery |
description | No | Truncated to 1024 characters on push to match the Runlayer API |
mcpServers | No | Inline MCP definitions take precedence over .mcp.json and are parsed the same way Runlayer already handled the old sidecar. |
How files map to Runlayer
skills/*/ become individual Runlayer skills
- supported non-skill files are bundled into one generated root skill named after the plugin
Supported root-skill file types:
.md
.txt
.sh
.py
.js
.ts
.json
Excluded from the root skill:
.claude-plugin/
skills/
.mcp.json
.lsp.json
settings.json
- root-level
README.md
Nested files like agents/README.md are included.
Runlayer first inspects mcpServers inside .claude-plugin/plugin.json and, if none are present, falls back to .mcp.json. Regardless of where the servers come from, only Runlayer proxy URLs are accepted:
{
"mcpServers": {
"crm": {
"url": "https://app.runlayer.com/api/v1/proxy/<server-uuid>/mcp"
}
}
}
Attached:
- URLs matching
/api/v1/proxy/<server-uuid>/mcp
Skipped:
- non-Runlayer MCP URLs
- stdio MCP entries
- plugin proxy URLs like
/api/v1/proxy/plugins/<plugin-uuid>/mcp
When you push a plugin that still defines non-Runlayer URLs, the CLI warns that those connectors were skipped; only the Runlayer proxies are recorded in the backend.
During plugins add, Runlayer regenerates the manifest mcpServers section with the proxy URL for the linked server(s), so the installed .claude-plugin/plugin.json and .mcp.json always point at the Runlayer endpoint even if the original source tooltip defined other entries.
Skipped non-Runlayer MCP URLs are shown as warnings during plugins push.
Publishing
uvx runlayer plugins push [PATH] --namespace <namespace> [OPTIONS]
| Flag | Description |
|---|
--namespace, -N | Required. Groups plugins by repo or source namespace |
--host, -H | Runlayer host URL. Also reads RUNLAYER_HOST |
--secret, -s | API key override (optional; prefer uvx runlayer login). Also reads RUNLAYER_API_KEY |
--public | Publish the plugin as public |
--dynamic-tools | Enable dynamic tools on the plugin |
--dry-run, -n | Show what would change without making writes |
--prune | Delete remote plugins missing locally |
PATH | Root directory to scan. Defaults to . |
Examples:
# Preview plugin changes
uvx runlayer plugins push --namespace myorg/repo -n
# Push plugins
uvx runlayer plugins push --namespace myorg/repo
# Push and remove remote plugins missing locally
uvx runlayer plugins push --namespace myorg/repo --prune
# Push a single plugin directory
uvx runlayer plugins push ./engineering --namespace myorg/repo
GitHub Actions
A common approach is to sync plugins automatically on every push to main. This keeps your Runlayer workspace in lockstep with your repo without any manual steps. Here’s a starter workflow you can adapt:
name: Push Plugins
on:
push:
branches: [main]
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uvx runlayer plugins push --namespace ${{ github.repository }} --prune
env:
RUNLAYER_HOST: ${{ secrets.RUNLAYER_HOST }}
RUNLAYER_API_KEY: ${{ secrets.RUNLAYER_API_KEY }}
Set RUNLAYER_HOST and RUNLAYER_API_KEY as repository secrets.
The --prune flag removes plugins from Runlayer when their directory is deleted from the repo.
Declarative sync semantics
Plugin skill membership is replaced from local disk.
- If a local plugin stops including one of its linked skills, that linked skill is removed from the remote plugin
- standalone skills in the same namespace are not deleted just because their path shares the plugin prefix
- only skills actually linked to the plugin are considered plugin-managed for deletion
Plugin connector membership is replaced from local .mcp.json.
- On plugin create, each imported Runlayer connector enables all tools currently visible on that server
- On plugin update, existing connectors keep their current selected tools
- On plugin update, newly added connectors enable all tools currently visible on that server
- If a connector is present locally and resolves to an accessible Runlayer server, it is attached
- if a connector is missing locally, it is removed remotely on update
.mcp.json controls connector membership, not per-tool curation for connectors that already exist remotely
The CLI warns when a push will remove remote connectors not present in the validated local plugin state.
--dry-run is a remote-aware preview:
- it reads remote plugin and skill state
- it prints
created, updated, unchanged, and deleted previews
- it does not write changes
With --prune, remote plugins not found locally are deleted, along with their linked skills. It does not delete unrelated standalone skills in the same namespace.
Warnings you may see:
truncated plugin description to 1024 characters
skipped MCP server <name> with non-Runlayer URL <url>
missing server <uuid> skipped
push will remove remote connectors not present in local plugin state: <uuid>
Installing
Add published plugins from the Runlayer API to your local project or global config.
uvx runlayer plugins add [SOURCE] [OPTIONS]
| Flag | Description |
|---|
source | Optional when --all is used. Plugin UUID or namespace (e.g. Org/Repo) |
--all | Install all accessible plugins across namespaces |
--plugin | Filter by plugin name within a namespace |
--client, -c | Target editor client (default: claude_code) |
--global, -g | Install globally instead of project-level |
--dry-run, -n | Show what would be installed without writing files |
--secret, -s | API key override (optional; prefer uvx runlayer login). Also reads RUNLAYER_API_KEY |
--host, -H | Runlayer host URL. Also reads RUNLAYER_HOST env var |
Supported clients
| Client | Install mode |
|---|
claude_code (default) | Native |
cursor | Native |
vscode | Native |
codex | Native |
windsurf | MCP fallback |
goose | MCP fallback |
zed | MCP fallback |
opencode | MCP fallback |
Native mode writes a plugin manifest and .mcp.json config file into the project or global directory. Codex uses a marketplace.json registry instead of symlinks. MCP fallback adds a server entry to the client’s MCP configuration file instead.
Examples
# Install all plugins from a namespace
uvx runlayer plugins add myorg/my-repo
# Install all accessible plugins across namespaces
uvx runlayer plugins add --all
# Install a single plugin by name
uvx runlayer plugins add myorg/my-repo --plugin release-tools
# Install globally
uvx runlayer plugins add myorg/my-repo --global
# Install for Cursor
uvx runlayer plugins add myorg/my-repo --client cursor
# Install for Codex
uvx runlayer plugins add myorg/my-repo --client codex
# Preview without writing files
uvx runlayer plugins add myorg/my-repo --dry-run
plugins add --all installs all accessible remote plugins. It does not affect how plugins list works.
File layout (native mode)
| Scope | Claude Code | Cursor | VS Code | Codex |
|---|
| Project | .claude/plugins/ | .cursor/plugins/ | .vscode/plugins/ | .agents/plugins/ |
| Global | ~/.claude/plugins/ | ~/.cursor/plugins/ | ~/.vscode/plugins/ | ~/.agents/plugins/ |
Manifest directories per client: .claude-plugin/, .cursor-plugin/, .vscode-plugin/, .codex-plugin/. Codex also writes a marketplace.json in the canonical plugins directory.
A lockfile at .runlayer/plugin-lock.yml (or ~/.runlayer/plugin-lock.yml for global) tracks installed plugins, install mode, and versions per client.
Interactive find
Browse and install plugins interactively from the terminal.
uvx runlayer plugins find
The command loads all available plugins, presents a searchable multi-select list, then prompts you to choose target clients and install scope (project or global). No flags are required — the wizard walks you through each step.
| Flag | Description |
|---|
--secret, -s | API key override. Also reads RUNLAYER_API_KEY |
--host, -H | Runlayer host URL. Also reads RUNLAYER_HOST |
Managing installed plugins
List
uvx runlayer plugins list [OPTIONS]
| Flag | Description |
|---|
--client, -c | Filter to one client |
--global, -g | List global plugins instead of project plugins |
By default, uvx runlayer plugins list shows installed plugins in the current project’s scope across all clients. Use --global to switch to global scope, or --client to filter the selected scope down to one client.
list is scope-first. update and remove stay client-scoped.
List examples
# List project plugins across all clients
uvx runlayer plugins list
# List global plugins across all clients
uvx runlayer plugins list --global
# List project plugins for one client
uvx runlayer plugins list --client cursor
# List global plugins for one client
uvx runlayer plugins list --global --client cursor
Update
Pull the latest versions of installed plugins from the API.
uvx runlayer plugins update [OPTIONS]
| Flag | Description |
|---|
--plugin | Update a specific plugin only |
--client, -c | Target editor client (default: claude_code) |
--global, -g | Update global plugins |
--dry-run, -n | Show what would change without writing files |
--secret, -s | API key override (optional; prefer uvx runlayer login). Also reads RUNLAYER_API_KEY |
--host, -H | Runlayer host URL. Also reads RUNLAYER_HOST env var |
Remove
uvx runlayer plugins remove [PLUGIN_REF] [OPTIONS]
| Flag | Description |
|---|
plugin_ref | Optional when --all is used. Plugin name or UUID to remove |
--all | Remove all installed plugins in the selected scope |
--yes | Skip confirmation prompt for --all |
--client, -c | Target editor client (default: claude_code) |
--global, -g | Remove from global plugins |
Remove examples
# Remove one plugin
uvx runlayer plugins remove release-tools
# Remove one plugin by UUID
uvx runlayer plugins remove a9d3ab20-4f5f-4d7b-a7b2-7b2b6f1d0d44
# Remove all project plugins (prompts for confirmation)
uvx runlayer plugins remove --all
# Remove all global plugins without prompt
uvx runlayer plugins remove --all --global --yes