feat: ship pay_mcp hermes plugin by default (CopyPlugins) + bump hermes v2026.6.19#657
Draft
bussyjd wants to merge 2 commits into
Draft
feat: ship pay_mcp hermes plugin by default (CopyPlugins) + bump hermes v2026.6.19#657bussyjd wants to merge 2 commits into
bussyjd wants to merge 2 commits into
Conversation
Latest hermes-agent release (2026-06-19; image verified published on Docker Hub). Bumps both pinned constants (agent_render.go defaultHermesImage, hermes.go defaultImage). Per the agent-contract integration test header, re-run flow-16-sell-agent.sh + internal/agentcrd contract test (bundled-skills-empty + marker invariants) before merging.
Embed the pay_mcp plugin in the obol-stack binary and seed it onto every agent's user-plugins dir, mirroring how embedded skills are seeded — so an agent can settle paid (x402) MCP tools out of the box. obol pins the upstream hermes image and can't ride the plugin in via the image, so we vendor + seed. - internal/embed: CopyPlugins + GetEmbeddedPluginNames (mirror CopySkills), embed internal/embed/plugins/pay_mcp (vendored, relative-imports invariant). - internal/hermes (master agent): syncObolPlugins seeds $HERMES_HOME/plugins; generateConfig sets plugins.enabled: [pay_mcp] (user plugins are opt-in). - internal/serviceoffercontroller + internal/agentcrd (sell sub-agents): renderHermesConfig enables pay_mcp; SeedHostPlugins seeds it on the host PVC. Inert unless the pod has REMOTE_SIGNER_URL (wallet-bearing agents only). - Tests: CopyPlugins (seed, no __pycache__, relative-imports-only, manifest name, preserve user plugins), config-enables-pay_mcp on both agent paths, SeedHostPlugins seed+preserve. Plugin stays inert without a signer, so it's safe to ship everywhere; users remain free to customize their own profile/plugins.
3567648 to
7604d76
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ship the
pay_mcphermes plugin by defaultThis makes obol-stack embed and seed the
pay_mcphermes plugin onto everyagent — the same way embedded skills are seeded — so an agent can settle paid
(x402) MCP tools out of the box, with no image rebuild and the user's profile
left untouched. obol pins the upstream
nousresearch/hermes-agentimage anddoesn't build it, so the plugin can't ride in via the image; we vendor it into
the binary and drop it into the agent's user-plugins dir on stack-up / reconcile.
The branch also folds in the
nousresearch/hermes-agentv2026.6.5 → v2026.6.19image bump (the image these agents run).
What pay_mcp does
A paid MCP server answers a tool call with an in-band x402 402 (the
amount/asset/payTo travels in
_meta). The plugin detects it, signs anEIP-3009
exactUSDC voucher through the pod's remote-signer (no keyin-process), retries with the voucher in
_meta["x402/payment"], and returnsthe paid result — so a 402 never surfaces to the agent. Settlement requires an
in-chat confirm by default; an opt-in unattended policy (per-call + session caps
How it integrates now
The plugin stays inert unless a signer is configured, so seeding it
everywhere is safe; sell sub-agents only get
REMOTE_SIGNER_URLwhenwallet-bearing.
Two non-obvious things this had to get right
kind: backendonly auto-loads when theplugin is bundled in the image; a plugin seeded into
~/.hermes/plugins/is
source=userand must be named inplugins.enabled. So seeding thefiles isn't enough — the generated config also writes
plugins.enabled: [pay_mcp]on both agent paths.package name
hermes_plugins.pay_mcp, and a stock image has no bundledplugins.pay_mcpto satisfy an absolute self-import. The plugin'sintra-package imports were converted to relative (
from . import x402) so itloads identically whether bundled or user-seeded. (Upstream fix:
bussyjd/hermes-agent@feat/pay-mcp-plugin; locked bytests/plugins/test_pay_mcp_userdir_load.py.)Changes
internal/embed—CopyPlugins+GetEmbeddedPluginNames(mirrorCopySkills); vendored plugin underinternal/embed/plugins/pay_mcp/(
VENDORED.mdrecords provenance + the relative-import invariant).internal/hermes(master agent) —syncObolPluginsseeds$HERMES_HOME/plugins;generateConfigaddsplugins.enabled: [pay_mcp].internal/serviceoffercontroller+internal/agentcrd(sell sub-agents) —renderHermesConfigenables pay_mcp;SeedHostPluginsseeds it on the host PVC.Test proofs
obol-stack (Go) — all green:
hermes-agent (Python) — inject-by-default integration, GREEN:
scripts/validate_pay_mcp_injection.pydrives the realPluginManageragainst an obol-seeded agent home (CopyPlugins layout +
plugins.enabled) whilesimulating a stock image (empty bundled dir + blocked core seam):
On-chain settlement (spark1, Base-Sepolia USDC) — 3 prior smokes GREEN:
crypto
0xba99dd88…, autonomous0xb22f8d84…, self-wire0xc5a8835f…(each Bob→Alice 1000 atomic USDC, balances verified exact). The runtime
settlement is already proven on-chain; this PR adds the seeding + enablement.
Remaining
A live spark1 master-agent redeploy with the rebuilt obol binary is the one
optional end-to-end confirmation not run here; every code path is covered by the
Go tests + the real-PluginManager integration validation + the prior on-chain
smokes.