#16558: feat(plugins): add sessions.spawn and rateLimit to plugin runtime
docs
stale
size: M
Cluster:
Tool and Plugin Enhancements
## Summary
Exposes two new capabilities on the plugin runtime:
### 1. `api.runtime.sessions.spawn()`
Plugins can spawn isolated agent sessions with restricted tool policies. This enables plugins to process external requests (webhooks, A2A messages, inter-agent communication) safely — the plugin controls which tools each session gets.
```ts
const result = await api.runtime.sessions.spawn({
message: "Check my calendar for free slots this week",
systemPrompt: "You are handling a request from a trusted friend's agent. Only use calendar tools.",
toolPolicy: {
allow: ["calendar", "web_search"],
deny: ["exec", "write", "message"],
},
timeoutSeconds: 60,
label: "a2a-calendar-check",
});
```
Uses the existing subagent infrastructure (`callGateway` → `agent` handler). No new execution machinery — just exposing what `sessions_spawn` already does internally, but accessible to plugins.
**Built-in safety guardrails:**
- Max 10 concurrent plugin-spawned sessions
- Max 20 spawns per minute (global across all plugins)
- Existing `tools.subagents.tools.allow/deny` config applies to all spawned sessions
### 2. `api.runtime.rateLimit.check()`
In-memory sliding-window rate limiter. Zero dependencies. Plugins provide the key (IP, sender URL, agent ID) and limits.
```ts
if (!api.runtime.rateLimit.check(`ip:${remoteAddress}`, { maxRequests: 30, windowMs: 60_000 })) {
return res.writeHead(429).end("Rate limited");
}
```
### Use case: A2A (Agent-to-Agent) protocol
We're building an [A2A plugin](https://github.com/Zephyr-Blessed/openclaw-a2a) that enables OpenClaw agents to communicate with other agents via Google's A2A protocol. A friend's agent can ask your agent to check your calendar and book a meeting — but a stranger's agent gets chat-only access with no tools.
This requires plugins to be able to route external messages through the LLM with controlled tool access, which isn't currently possible.
### Discussion: Config gating?
We considered adding a config toggle (e.g. `plugins.allowSessionSpawn: true`) but decided against it because:
- No existing `PluginRuntime` method requires config opt-in
- Plugins are treated as trusted code ("treat them as trusted code" per docs)
- The existing `tools.subagents.tools` config already controls spawned session tool access
- Plugin installation itself (`plugins.allow/deny`) is the trust gate
**Question for maintainers**: Would you prefer a config gate here? We're happy to add one if the team feels it's warranted. The hardcoded concurrency/rate limits provide basic safety regardless.
### Files changed
| File | Change |
|------|--------|
| `src/plugins/runtime/types.ts` | New types: `PluginSessionSpawnOptions`, `PluginSessionSpawnResult`, `RateLimitOptions` |
| `src/plugins/runtime/index.ts` | Implementation: `spawnPluginSession`, `rateLimitCheck/Reset`, concurrency guards |
| `src/plugin-sdk/index.ts` | Export new types |
| `docs/tools/plugin.md` | Documentation with examples |
| `src/plugins/runtime/rate-limit.test.ts` | Rate limiter tests |
### Note on tool policy override
The current implementation passes `toolPolicy` via `sessions.patch` before spawning. If `sessions.patch` doesn't support `toolPolicy` yet, the session falls back to the default subagent tool policy (which already denies `sessions_spawn`, `gateway`, `cron`, `memory_*`, etc.). The `extraSystemPrompt` provides additional guidance to the LLM.
A follow-up PR could add `toolPolicyOverride` to the `agent` gateway method for runtime-enforced per-session tool restrictions.
---
*This PR is part of the [OpenClaw A2A plugin](https://github.com/Zephyr-Blessed/openclaw-a2a) project — enabling inter-agent communication via Google's A2A protocol.*
Most Similar PRs
#23506: feat(spawn): per-spawn tool permissions for sessions_spawn
by dissaozw · 2026-02-22
74.0%
#21035: feat: agent hardening — modifying after_tool_call hook, cron contex...
by roelven · 2026-02-19
71.7%
#17666: feat(plugins): expose steerSession and isSessionStreaming on plugin...
by mconcat · 2026-02-16
71.6%
#21136: fix(security): harden agent autonomy controls
by novalis133 · 2026-02-19
71.2%
#10748: feat: Add sessions.spawn gateway method for direct subagent spawning
by fox-openclaw · 2026-02-06
70.5%
#18911: feat(plugins): Add registerStreamFnWrapper and updatePluginConfig APIs
by John-Rood · 2026-02-17
69.8%
#13331: feat(sessions_spawn): add sessionKey param to reuse sub-agent sessions
by Be1Human · 2026-02-10
69.2%
#20072: feat(sessions_spawn): add sessionKey param to reuse sub-agent sessions
by Be1Human · 2026-02-18
69.0%
#16044: plugin-sdk: expose onAgentEvent + onSessionTranscriptUpdate via Plu...
by scifantastic · 2026-02-14
69.0%
#18860: feat(agents): expose tools and their schemas via new after_tools_re...
by lan17 · 2026-02-17
68.2%