Experimental. tinyagent can load Agent Plugins: directories with a plugin.json manifest that bundle skills. List them in the config:
skills: true
plugins:
- path: /home/me/plugins/release-kit-
pathmust be absolute and an existing directory; the same directory listed twice (after resolving symlinks) is a config error, as are unknown keys. A profile'splugins:replaces the base list. -
The manifest is validated (
$schema,name, optionalversion). A plugin with an invalid or missing manifest is skipped with a warning; unknown manifest fields only warn. Two plugins with the samenameare a config error (exit 2). -
With
--skills, skills under<plugin>/skills/join the catalog with the lowest precedence (see Agent Skills). Skill folders or askillsdirectory that resolve outside the plugin root are skipped with a warning. -
MCP servers. A plugin's
mcp.jsonservers start only when listed under that plugin'smcp_servers, with an explicit allowlist, exactly likemcp_serversentries:plugins: - path: /home/me/plugins/review-kit mcp_servers: - server: validator # key in the plugin's mcp.json alias: reviewkit # tools appear as reviewkit__<tool> tools: [lint, explain] resources: ["validator://rules/*"] # optional discovery_timeout_seconds: 15 # optional call_timeout_seconds: 60 # optional
- Only
stdioservers run.streamable-httpandsseentries are reported as unsupported and skipped. A./command must stay inside the plugin; other commands are bare names found onPATH, never run through a shell. - The server's working directory is the plugin root unless
cwd(./...,${PLUGIN_ROOT}/...or${PLUGIN_DATA}/...) says otherwise.PLUGIN_ROOTandPLUGIN_DATAare set for the server (a plugin can't override them) and expanded once inargs,envvalues andcwd.envvalues frommcp.jsonare set as given, on top of the usual minimal MCP environment. PLUGIN_DATAis./.tinyagent/plugin-data/<name>inside--cwd(for example./.tinyagent/plugin-data/review-kit), created with mode 0700 before the first launch and kept between runs; delete it to reset the plugin's data. Add.tinyagent/to your.gitignore. If.tinyagentor.tinyagent/plugin-datais a symlink that leads outside--cwd, the run stops with a config error naming the plugin. Hard cut: earlier versions used<user config dir>/tinyagent/plugin-data/<name>(for example~/.config/tinyagent/plugin-data/review-kit); that folder is no longer used or copied. When it exists, a run with plugin MCP servers prints one stderr line,hint: plugin data in <old path> is no longer used; PLUGIN_DATA is now ./.tinyagent/plugin-data/<name> in --cwd (copy a plugin's folder there to keep it); copy the folder yourself to keep a plugin's data.- An invalid
mcp.jsondisables only that plugin's MCP servers, and an invalid entry only that entry, with a warning. A listed server that is missing, invalid or unsupported, a rejected plugin withmcp_servers, an alias already used by another server, or more than 8 servers in total exits 2 before any model request. - Plugin servers otherwise follow every
mcp_serversrule: read-only runs and resumed runs don't start them, and lockdown, hooks and tool output handling apply.
- Only
-
-vprints each loaded plugin; warnings go to stderr and, with--json, aswarningevents. -
Inspection.
tinyagent --list-plugins [-c <file>] [--profile <name>]prints, per plugin, its path, name and version andok,warnings: Norrejected: <reason>; each plugin skill (and which skill shadows it); and eachmcp.jsonserver with its type and state:authorized as <alias> (N tools),not authorized,unsupported transportorinvalid: <reason>. It makes no model request, needs no credentials, starts no servers or hooks and writes nothing (not evenPLUGIN_DATA). It exits 0 when every plugin loads, 1 when a plugin is rejected or a configured server is missing or invalid, and 2 on a config error or when combined with-t,--resumeor another mode.--checkprints aplugins:line (configured, rejected and authorized server counts) and fails on the same errors that stop a run. -
Records.
run.started(and so--jsonand--log-db) and-otrajectories gainplugins: each loaded plugin'sname,version,path,plugin_json_sha256,mcp_json_sha256(when it has one),skills(its skills in the catalog, with--skills) andmcp_servers(server,alias).mcp.jsonenvvalues are never recorded. With nopluginskey nothing is added. -
Resume. A changed skills catalog refuses to resume as usual. A changed
plugin.jsonormcp.jsondigest only warns, naming the plugin. -
Versions of tinyagent without plugin support reject the
pluginskey as unknown.
Trust: a plugin is code and prompt input you chose to install. Its MCP servers run with your permissions and are not sandboxed by --sandbox, like configured MCP servers. Only list plugins you trust.
Plugins can also ship code modules that run as WebAssembly through Extism, never inside the tinyagent process. Full reference: wasm-plugins.md.
- Declaring and loading.
plugin.jsondeclares modules underextensions.tinyagent.wasm_modules, and the config authorizes them by name (wasm_modules). Each module's requested permissions (paths, hosts, WASI, host functions) must fit a grant derived from the session (--cwdandfile_accesspaths,sandbox_allowed_domainshosts, no host functions); a refused module prints a warning and other plugins still load. Exports become<plugin>__<export>tools, like MCP tools. They are refused once the session is tainted, and--read-onlyruns load no modules. When a plugin is reactivated, unchanged modules are reused and changed ones are swapped in with the permissions from the first load pinned. - Version store. Every module version is kept, append-only, under
<cwd>/.tinyagent/modules/<plugin>__<module>/as<sha256>.<ext>files that are never overwritten, each with a.meta.jsonsidecar.pinned.jsonrecords the first-load permissions and acurrentpointer (written atomically) selects the active version. A changed module file is stored as a new version (refused if it asks for more than the first load); a stored file whose hash doesn't match is refused. - Rollback.
tinyagent plugins rollback <module> <sha256>(--plugins-rollback <module>@<sha256>) moves the pointer back to a stored version. It is refused if that version needs wider permissions than the first load, if its hash doesn't match, or after taint. - Prune.
tinyagent plugins prune [--keep N](--plugins-prune [--plugins-keep N]) removes old versions, keeping the current one and the newest N others (default 5). The current version is never removed. - Go source modules (TinyGo). A module can be given as Go source (
"source": "<dir>", "lang": "go"). tinyagent compiles it to.wasmwith TinyGo inside the OS sandbox (writes confined, network denied), stores the build in the version store and loads it through the same permission check. TinyGo is an external dependency, shipped separately by the TinyGo project and not part of tinyagent: it is never embedded in the tinyagent binary or repository. tinyagent downloads a pinned TinyGo release on first use (or withtinyagent tinygo install), verifies its SHA-256 checksum before extracting it, and caches it in./.tinyagent/cache/toolchainsinside--cwd(add.tinyagent/to your.gitignore). Hard cut: the old cache under the user cache directory (tinyagent/toolchains/) is no longer used; when it exists, one stderrhint:line names the new location and the pinned release is downloaded again (see Managing TinyGo).tinyagent tinygo updatemoves to the version pinned in the current build, andtinyagent tinygo statusshows what is installed. To use your own TinyGo, set thetinygoconfig key orTINYAGENT_TINYGO. TinyGo also needs a Go toolchain onPATH.