-
Notifications
You must be signed in to change notification settings - Fork 1
features plugins
A plugin is an installable bundle that extends eVi without touching your own configuration directories. One plugin can ship any mix of:
-
slash commands — exposed as
/<plugin>:<command> - skills — markdown instruction packets the model loads on demand
- hooks — before/after-tool-call hooks
- MCP servers — namespaced tool providers
-
subagent profiles — used through the
delegatetool
Use plugins when you want to share or reuse a coherent set of capabilities (e.g. a "git-helpers" bundle of git slash commands) instead of hand-copying individual command files, skills, and config snippets. The marketplace is a thin, optional layer on top: a searchable name → source index so you can evi plugin search and evi plugin install <name> instead of pasting directory paths or git URLs.
Everything is local-first and single-user. Installed plugins live under your eVi home (~/.evi/), and nothing is fetched at runtime except the optional remote index files you explicitly configure.
Each plugin is just a directory containing a plugin.toml manifest. Installed plugins live at:
~/.evi/plugins/<name>/
Component types are auto-discovered from well-known sub-paths inside the plugin directory:
| Path inside the plugin | Component | Surfaced as |
|---|---|---|
commands/**/*.md |
slash commands | /<plugin>:<command> |
skills/<name>/SKILL.md |
skills |
<plugin>:<skill> in the skill index |
hooks.toml |
before/after-tool hooks | merged after your own ~/.evi/hooks.toml
|
mcp.json |
MCP servers | namespaced <plugin>:<server>
|
agents.toml |
subagent profiles | namespaced <plugin>:<name> (via delegate) |
The manifest itself is minimal:
# ~/.evi/plugins/git-helpers/plugin.toml
name = "git-helpers"
description = "Handy git slash commands"
version = "0.1.0"Install is just directory management. evi plugin add reads the manifest, validates the name (must match [A-Za-z0-9_-]+), and copies the source into ~/.evi/plugins/<name>/ (the .git directory is stripped). If a plugin with that name already exists, it is replaced. evi plugin remove deletes the directory. There is no copying into your own commands/, skills/, etc. — so there's no clobbering of your personal files.
Loaders scan plugin directories live. The command, skill, hook, MCP, and subagent loaders each rescan ~/.evi/plugins/ on use:
- The skill loader (
evi/skills.py) and command loader (evi/commands.py) prefix every plugin component with<plugin>:. - The hook loader (
evi/hooks.py) parses each plugin'shooks.tomlafter your own hooks, appending them to the registry. - The MCP loader (
evi/mcp/servers.py) parses each plugin'smcp.json, prefixing each server name with<plugin>:. - The subagent loader (
evi/llm/subagent.py) parses each plugin'sagents.toml, namespacing each profile<plugin>:<name>.
Because loaders rescan on every call, freshly added plugins appear without restarting long-lived processes (the web/desktop server).
The marketplace index (evi/marketplace.py) is plain JSON mapping a plugin name to where it can be installed from. The local index lives at ~/.evi/marketplace.json; you may also configure extra remote index URLs that are fetched and merged in. On a name clash, the local entry wins. Remote fetches are best-effort with a 10-second timeout — a flaky or bad URL is silently ignored and never breaks search. evi plugin install <name> resolves the name through the merged index to its source, then hands that to the same installer used by evi plugin add.
| Path | What it is |
|---|---|
~/.evi/plugins/<name>/ |
An installed plugin (directory with a plugin.toml) |
~/.evi/marketplace.json |
The local plugin index (optional; created by evi plugin index init) |
~/.evi/config.toml |
Main config; holds the [plugins] section |
On Windows, ~/.evi/ resolves to %USERPROFILE%\.evi\.
The only configurable key for this feature area is index_urls — a list of extra remote plugin-index JSON files merged with the local ~/.evi/marketplace.json:
# ~/.evi/config.toml
[plugins]
index_urls = ["https://example.com/evi-plugins.json"]Default: index_urls = [] (empty — only the local ~/.evi/marketplace.json is consulted). No remote calls happen unless you add URLs here.
{
"plugins": [
{
"name": "git-helpers",
"source": "https://github.com/you/evi-git-helpers.git",
"description": "Handy git slash commands",
"author": "you",
"tags": ["git", "vcs"]
}
]
}Only name and source are required per entry; description, author, and tags are optional. A remote index file uses the exact same shape.
None. Plugins and the marketplace use only the standard library (tomllib/tomli, json, urllib, subprocess for git clone). Installing a plugin from a git URL requires git to be available on your PATH.
All commands are part of the evi CLI, under the evi plugin group.
evi plugin add <dir|git-url> [--name NAME] Install from a local dir or git URL
evi plugin list List installed plugins + component counts
evi plugin remove <name> Remove an installed plugin
-
evi plugin addtakes a local directory or a git URL (URLs starting withhttp://,https://,git@,ssh://, or ending in.gitare treated as git and shallow-cloned).--nameoverrides the name from the manifest. -
evi plugin listprints each plugin with its version and a count summary, e.g.(3 cmds, 1 skills, 2 hooks).
evi plugin search [query] Search the merged index by name/desc/tag
evi plugin install <name> Install by name via the index
-
evi plugin searchwith no query lists every entry; with a query it does a case-insensitive substring match over name, description, and tags. -
evi plugin installresolves the name through the local index plus any configuredindex_urls, then installs the resolvedsource.
evi plugin index init [--overwrite] Write a starter ~/.evi/marketplace.json
evi plugin index add <name> <source> [--desc D] Add/replace a local index entry
[--author A]
[--tags t1,t2]
-
evi plugin index initwrites a startermarketplace.json(refuses to overwrite an existing file unless you pass--overwrite). -
evi plugin index addadds or replaces an entry by name.--tagstakes a comma-separated list.
The web and desktop apps have a Settings → Plugins panel (no CLI needed):
- lists installed plugins with their component counts (commands / skills / hooks / MCP / agents) and a Remove button each;
- a Marketplace list with a filter box and per-entry Install button (entries you already have are marked installed);
- an Install from a directory or git URL field for one-off installs.
It is backed by GET /api/plugins and POST /api/plugins/{install,remove} —
the same evi.plugins / evi.marketplace functions the CLI uses.
-
Slash commands appear as
/<plugin>:<command>in the REPL and web UI. -
Skills appear in the skill index as
<plugin>:<skill>; the model loads one viainvoke_skill(name). -
Subagent profiles appear in
evi agentsas<plugin>:<name>and are invoked through thedelegatetool. - Hooks and MCP servers are loaded automatically and need no extra command.
Create a small plugin that ships one git slash command:
mkdir -p my-plugin/commands
cat > my-plugin/plugin.toml <<'EOF'
name = "git-helpers"
description = "Handy git slash commands"
version = "0.1.0"
EOF
cat > my-plugin/commands/changelog.md <<'EOF'
Summarize the git commits since the last tag as a changelog.
EOFInstall it and confirm:
evi plugin add ./my-plugin
# installed git-helpers
# its commands are now /git-helpers:<command> (see `evi plugin list`)
evi plugin list
# git-helpers v0.1.0 (1 cmds) — Handy git slash commandsNow /git-helpers:changelog is available as a slash command in the REPL and web UI. To uninstall:
evi plugin remove git-helpers
# removed git-helpersCreate a local index, add an entry, search it, and install:
evi plugin index init
# created C:\Users\you\.evi\marketplace.json
evi plugin index add git-helpers \
https://github.com/you/evi-git-helpers.git \
--desc "Handy git slash commands" \
--author you \
--tags git,vcs
# indexed git-helpers -> https://github.com/you/evi-git-helpers.git
evi plugin search git
# git-helpers · you #git #vcs
# Handy git slash commands
# https://github.com/you/evi-git-helpers.git
evi plugin install git-helpers
# installed git-helpers (from https://github.com/you/evi-git-helpers.git)Point eVi at a hosted index (e.g. a team-shared list) so its plugins show up in search and install-by-name alongside your local entries:
# ~/.evi/config.toml
[plugins]
index_urls = ["https://example.com/evi-plugins.json"]evi plugin search # lists local + remote entries, sorted by name
evi plugin install <name> # resolves through the merged indexIf the URL is unreachable, search and install still work using just your local index.
-
Single config key. The only
[plugins]config option isindex_urls. There is no enable/disable flag, no allow-list — installed plugins (anything under~/.evi/plugins/<name>/with a validplugin.toml) are always active. -
No version pinning or update command. Installing a plugin that already exists replaces it (the old directory is removed first). To "update," just
evi plugin add/evi plugin installagain. There is noevi plugin update. -
Local entries win on name clash. When merging remote
index_urlswith~/.evi/marketplace.json, an entry already present locally takes precedence. - Remote fetches are fail-open. Remote index fetches use a 10-second timeout and swallow all errors — a bad or slow URL returns nothing rather than raising, so search/install never break. Malformed local index JSON is likewise treated as empty.
-
Security — install runs
git clone. Installing from a git URL shells out togit clone --depth 1. Installing a plugin means trusting its contents: plugins can register hooks that run around tool calls and MCP servers that are real processes/endpoints. Only install plugins from sources you trust, and reviewhooks.toml,mcp.json, andagents.tomlbefore relying on a third-party bundle.index_urlspoint at JSON you control or trust; the JSON only lists install sources, but those sources are what gets cloned. -
Name validation. Plugin names must match
[A-Za-z0-9_-]+. A git URL like…/evi-git-helpers.gitis slugged toevi-git-helpers(the.gitsuffix and path are stripped) unless you override with--name. -
Malformed components are skipped, not fatal. When counting/loading components, an absent or malformed
hooks.toml,mcp.json, oragents.tomlsimply contributes zero — a broken optional file in one plugin won't stop others from loading. A plugin directory with no validplugin.tomlis ignored byevi plugin list. -
No clobbering of personal files. Plugins are never merged into your own
~/.evi/commands/,~/.evi/skills/, etc. Their components are discovered in place under~/.evi/plugins/<name>/and namespaced with the<plugin>:prefix, so they can't shadow your own commands or skills.
Generated from docs/features/plugins.md — edit there, not here.
Start here
Guides
- Architecture
- [[Agent SDK (
evi.sdk)|sdk]] - SDK coverage + borrowable features
- Multi-machine setup
- Self-update design (Phase 29 proposal)
- [[Self-build — developing and building eVi with eVi|self-build]]
- Development notes
- Releasing
- Desktop bundling
- Code signing policy
- Surface parity — CLI ↔ Web ↔ Desktop
- eVi vs Claude Code — feature comparison
- Future integrations — backlog
- Roadmap
Feature deep-dives
- eVi feature guides
- Agents & Orchestration
- Recipes, Routines, Scheduled tasks, Channels
- Evals & LLM-as-judge
- Content Guardrails
- Hooks (tool + lifecycle, command/url)
- MCP (client + serve)
- Memory & Context management
- Observability (OpenTelemetry, stats, crash reports)
- Permissions & Sandbox
- Plugins & Marketplace
- Sessions, Resume, Handoff, Checkpoints
- Skills
- Slash commands
- Structured Outputs & Batch
- Ultracode
- Voice (TTS engines, STT, AutoSpeaker)
- Web & Desktop (settings, multi-user, deep links, updater)