Installed Plugins and Marketplaces¶
If a harness can install a plugin or a marketplace, ai-rulez can import it, use it and lock it. An
[[installed_marketplaces]] entry names a plugin marketplace; an [[installed_plugins]] entry imports one
plugin, from a marketplace or straight from a repository. The skills, agents, commands, rules, hooks and MCP servers
the plugin ships become ordinary ai-rulez content, rendered into every preset you generate, pinned in
ai-rulez.lock and covered by the same security scan as installed skills.
This is the consumer side. To build a plugin from your own content, see Plugins
(ai-rulez generate --plugin).
Quick start¶
[[installed_marketplaces]]
name = "acme"
source = "acme/plugins" # GitHub owner/repo; or a git URL, ./local/dir, https://.../marketplace.json
version = "^1.2" # optional: a tag range, moved only by `ai-rulez update`
[[installed_plugins]]
name = "formatter"
marketplace = "acme"
exclude = ["hooks"] # skills, agents, commands, hooks, mcp, rules
[[installed_plugins]]
name = "review-tools"
source = "https://github.com/acme/review-tools" # a plugin repository, no marketplace
ref = "v2.0.1"
enable_hooks = true # hooks are off unless you opt in
ai-rulez marketplace add acme --source acme/plugins
ai-rulez plugin install formatter --from acme
ai-rulez lock # pins the marketplace and the plugin (commit + tree digest), scans both
ai-rulez generate
Formats¶
| Harness | Marketplace index | Plugin manifest | What is imported |
|---|---|---|---|
| Claude Code | .claude-plugin/marketplace.json |
.claude-plugin/plugin.json (optional) |
skills/, agents/, commands/, hooks/hooks.json, .mcp.json, plus the skills, agents, commands, hooks and mcpServers paths or inline objects the manifest names |
| Codex | .agents/plugins/marketplace.json |
.codex-plugin/plugin.json |
skills/, .mcp.json, hooks.json and the manifest's skills, mcpServers and hooks fields |
| Cursor | .cursor-plugin/marketplace.json |
.cursor-plugin/plugin.json |
rules/ (as rules), agents/, skills/, commands/, hooks/hooks.json, .mcp.json or mcp.json |
| Gemini CLI extension | none | gemini-extension.json |
mcpServers, the contextFileName file(s) (as a rule), commands/*.toml (as commands), skills/, agents/ |
| Agent Plugins | none | root plugin.json with an agent-plugins.org $schema |
skills/, mcp.json and the com.anthropic.claude-code (agents, commands, hooks) and io.github.goldziher.ai-rulez (rules) extension namespaces |
The layout is detected from the manifest; format forces it. A directory with Claude's default directories and no
manifest is a Claude plugin, as Claude Code treats it. A marketplace entry with strict = false that declares its
own components needs no manifest in the plugin directory.
Skills are bundled whole, exactly like an installed skill.
Agent, command and rule files keep their frontmatter. A nested command git/commit.md is named git-commit. A
Gemini TOML command becomes a prompt: its {{args}} and !{...} placeholders are kept as written.
Source forms¶
source of a marketplace or plugin accepts:
| Form | Example |
|---|---|
| GitHub shorthand | acme/plugins, github:acme/plugins |
| Git URL | https://github.com/acme/plugins, git@github.com:acme/plugins.git, file:///srv/plugins |
| Local directory | ./vendor/marketplace (must start with ./, ../ or /; inside the project) |
| Index URL (marketplace only) | https://example.com/marketplace.json |
A bare owner/repo is GitHub, as in Claude Code. The same safety rules as installed skills apply: https only (no
http://), no credentials in a URL, no git option or transport helper such as ext::, no .. in a path, and a
local path from the committed config must stay inside the project (the machine-local overlay and the user config may
leave it). file:// repositories outside the project need AI_RULEZ_ALLOW_FILE_URLS=1.
A marketplace entry names its plugin as:
- a relative path inside the marketplace repository (
"./plugins/x";metadata.pluginRootis prepended to a bare name), {"source": "github", "repo": "owner/repo", "ref": "...", "sha": "..."},{"source": "url" | "git", "url": "...", "ref": "...", "sha": "..."},{"source": "git-subdir", "url": "...", "path": "sub/dir"}, or Codex's{"source": "local", "path": "./x"}.
A relative path that is absolute, contains .. or goes through a symlink is refused, so an index cannot make
ai-rulez read outside the marketplace repository. An entry with a source type ai-rulez does not support (npm, pip) is
listed as not installable.
Entry fields¶
[[installed_marketplaces]]: name, source, path (directory holding the index), ref, version, tag_prefix,
include_prerelease, min_release_age, trust.
[[installed_plugins]]: name, then either marketplace (and plugin when the entry is called otherwise) or
source, path, ref, version, tag_prefix, include_prerelease, min_release_age; and format, include /
exclude (component kinds), name_prefix, domain, profiles, trust, enable_hooks (default false),
enable_mcp (default true).
A plugin installed from a marketplace follows the marketplace's ref/version; setting them on the plugin is an
error. domain and profiles scope skills, agents, commands, rules and MCP servers like
installed skills; hooks are global. A name that already exists (local content first, then
earlier plugins) wins and the later one is skipped with a warning; use name_prefix to keep both. The prefix is part of the name and of the skill's output directory
(.claude/skills/<prefix><dir>/).
Hooks, MCP servers and permissions¶
- Hooks are off by default. A hook runs a command on every machine that uses the project, so, as with
convert --enable-hooks, they are imported only withenable_hooks = true. A plugin with hooks that are not enabled is reported once. Imported hooks are restricted to the harness they were written for. - MCP servers are imported unless
enable_mcp = false. Literal credentials inenv,args,urlorheadersare replaced by${VAR}references and reported; the servers go through the same MCP checks and[mcp]policy as your own. ${CLAUDE_PLUGIN_ROOT}. The plugin directory does not exist in the generated tree, so a hook or MCP server that refers to it (${CLAUDE_PLUGIN_ROOT},${CODEX_PLUGIN_ROOT},${PLUGIN_ROOT}, Gemini's${extensionPath}) is rewritten to the project-relative path of the plugin only when the plugin is a local directory inside the project (source = "./vendor/tools"). For a fetched plugin the hook or server is refused and reported (AR9F3), never written pointing at nothing.${CLAUDE_PLUGIN_DATA}is always refused.- Permissions are never imported: a plugin cannot add an allow rule.
Security model¶
- Fetches use the include machinery: the same git cache, credential handling (a token goes only to allowlisted hosts) and
sources.allowed_hosts/sources.deny_hostspolicy, which also applies to a repository a marketplace names. - Before
ai-rulez lockpins a new tree it runs the security scan (AR001-AR009) over every file of the marketplace or plugin, hook scripts and MCP definitions included; error findings refuse the pin (exit 2) unless--accept-findings. The entry'strustsets the level (errormakes every finding an error; a plugin inherits its marketplace's). generatescans the imported content again, plus the hook documents, MCP documents and the scripts they run, at the same level ([lint.security] scan_imports).- Symlinks are never followed, files and manifests are size-bounded, names are validated, and a malformed manifest fails the load with an error naming the file.
- The organization policy's hooks and
[mcp]limits bound plugin hooks and servers (AR748);sources.deny_digestsand approvals apply tomarketplaceandinstalled-pluginentries.
Lock, update and refresh¶
ai-rulez lock pins marketplaces and plugins fetched from a remote repository or an https URL in ai-rulez.lock, as
[[marketplace]] and [[plugin]] entries: the commit, the requested ref or constraint, the resolved tag and a tree
digest. A plugin installed from a marketplace is keyed
marketplace:<name> and records the repository the index named for it as origin; a plugin inside the marketplace
repository shares its commit and has its own digest. An https marketplace.json has a digest and no commit.
- What is pinned, by source kind. A remote repository:
[[marketplace]]/[[plugin]]entries with commit and tree digest. An httpsmarketplace.json: a digest, no commit. A local directory inside the project (source = "./vendor/market"): no[[marketplace]]or[[plugin]]entry, but alocal-marketplaceorlocal-pluginitem holding the tree digest of the directory (a plugin of a local marketplace is covered by the marketplace item). Editinghooks/hooks.json, a hook script or any other file in it makeslock --checkandgenerate --lockedfail untilai-rulez lockis rerun. An installed skill read from a local directory is pinned as alocal-skillitem. generate --locked/--frozenand an enforced lock fail on a missing, stale or mismatching pin (a moved branch, a retagged release, changed bytes);--offlinereads the cache only.ai-rulez lock --checkcompares the lock offline;ai-rulez lock [name]/--kind marketplace|pluginrefreshes. Refreshing a marketplace refreshes the plugins installed from it.ai-rulez update [--kind marketplace|plugin] [name]moves entries that use aversionrange to the newest allowed tag (see Lock file);marketplace updateandplugin updatere-pin plain refs.ai-rulez sbomandapprovelist these entries.
CLI¶
See the CLI reference. To change an entry for one machine only, edit config.local.toml.
Migrating from [[plugins]] / [[marketplaces]]¶
In v4 the [[plugins]] and [[marketplaces]] tables described plugins to enable in a harness and were never read
by v5 beyond a warning. They do not import anything. Replace a [[marketplaces]] entry by
[[installed_marketplaces]] (name, source) and a [[plugins]] entry name@marketplace by
[[installed_plugins]] with marketplace set. Enabling a plugin in the harness itself is separate: keep that in the
harness settings.