How ActionSpec Works
ActionSpec is an optional, on-demand spec-packeting subsystem. When an agent needs to use a plugin, ActionSpec provides a structured catalog of available actions, input schemas, risk levels, and execution templates — so the agent picks the right tool call on the first try.
- Optional activation: spec lookup only fires when plugin/tool execution is needed. Normal chat never triggers it.
- Graceful fallback: if no
actionspec.jsonexists, the runtime infers actions fromplugin.json, runtime describe, and bounded source scanning. - Risk-tiered confirmation: inferred actions classified as
write,destructive, orsecurity_sensitiverequire explicit user confirmation before execution. - Packet replacement: repeated spec lookups reuse cached packets with stable
packet_id, reducing token overhead.
Plugin File Layout
plugins/installed/<plugin_id>/
plugin.json # Required — plugin manifest
actionspec.json # Recommended — action catalog with schemas
skill.json # Optional — skill routing hints
README.md # Optional — short description pointer
src/
index.ts # Entry point
plugins/plugins.registry.json # Auto-generated spec registry
skills/specs/<skill_id>.json # Optional SkillSpec JSON files
state/spec_packets/ # Packet cache (local-only, auto-managed)The plugins.registry.json file is regenerated automatically on startup, plugin install, enable, disable, and uninstall. You never need to edit it manually.
plugin.json — Manifest with Spec Block
Add an optional spec block to your existing plugin.json to point at your ActionSpec and SkillSpec files. Existing manifests without this block continue to work unchanged.
{
"id": "hello-world",
"name": "Hello World Plugin",
"version": "1.0.0",
"description": "Sample plugin that returns a greeting and echoes input.",
"author": "ClawMagic",
"entry": "src/index.ts",
"capabilities": ["local-demo"],
"tools": ["local_read_file"],
"requiresApprovalToCreate": true,
"requiresApprovalToRun": false,
"permissions": {
"filesystem": {
"read": ["workspace/*"],
"write": ["plugins/installed/hello-world/**", "worklogs/**"]
},
"network": { "allow": [] }
},
"spec": {
"actionspec_path": "actionspec.json",
"readme_path": "README.md",
"skill_path": "skill.json"
}
}The spec block is validated but never required. Plugins without it fall back to code inspection automatically.
actionspec.json — Action Catalog
Each action entry describes one callable operation: what tool it maps to, what inputs it accepts, how risky it is, and what the agent should verify after execution.
{
"schema_version": "cm.actionspec.v1",
"plugin_id": "hello-world",
"namespace": "plugins.hello_world",
"actions": {
"hello.run_echo": {
"title": "Run Hello Plugin",
"description": "Execute plugin and return greeting plus echoed input.",
"tool_name": "plugins.run",
"tool_args_template": {
"pluginId": "hello-world",
"input": { "input": "${input}" },
"spec_action_key": "hello.run_echo"
},
"inputs_schema": {
"type": "object",
"properties": {
"input": { "type": "object", "additionalProperties": true }
},
"required": []
},
"constraints": [
"Plugin must be installed and enabled.",
"Do not pass secrets in input."
],
"procedure": [
"Optionally verify plugin enabled state.",
"Invoke plugins.run with templated args.",
"Return message and echoed input."
],
"verification_steps": [
"Result contains a greeting string.",
"Result includes the echoed input object."
],
"fallback": [
"If plugin is disabled, call plugins.enable or ask user.",
"If run fails, return concise error and next action."
],
"examples": [
{ "input": { "input": { "ping": true } } },
{ "input": { "input": { "name": "Shawn" } } }
],
"danger_level": "read_only",
"requires_confirmation": false,
"tags": ["demo", "plugin-run", "read"]
}
}
}Action Fields Reference
| Field | Required | Purpose |
|---|---|---|
title | Yes | Human/agent-readable action name |
description | Yes | What this action does |
tool_name | Yes | Runtime tool to invoke (e.g. plugins.run) |
tool_args_template | Yes | Fixed + variable args for the tool call |
inputs_schema | Yes | JSON Schema for variable inputs |
danger_level | Yes | read_only, write, destructive, or security_sensitive |
requires_confirmation | Yes | Whether agent must confirm before executing |
constraints | No | Preconditions the agent should check |
procedure | No | Step-by-step execution guidance |
verification_steps | No | How to verify the action succeeded |
fallback | No | What to do if the action fails |
examples | No | Sample input payloads for the agent |
tags | No | Searchable labels for action discovery |
skill.json — Plugin-Local Skill Hints
A skill.json file tells the agent when this plugin is useful and which action keys to prioritize. It is optional — the agent can discover actions without it.
{
"schema_version": "cm.plugin.skill.v1",
"plugin_id": "hello-world",
"goal": "Provide a deterministic hello-world plugin execution path.",
"when_useful": [
"Validating plugin runtime wiring",
"Smoke testing plugin execution"
],
"recommended_action_keys": [
"hello.check_enabled",
"hello.run_echo"
],
"optional_for_execution": true
}SkillSpec JSON — System-Level Skill Routing
SkillSpec files live in skills/specs/ and route high-level user goals to specific plugins and actions. They operate above the plugin layer.
{
"schema_version": "cm.skillspec.v1",
"skill_id": "plugin-smoke-test",
"goal": "Run a safe plugin smoke test and report result.",
"routing_hints": ["plugin", "validation", "local"],
"success_criteria": [
"Plugin selected correctly",
"One safe action executed",
"Output summarized for user"
],
"tags": ["plugin", "diagnostics"],
"plugin_support": [
{
"plugin_id": "hello-world",
"optional": true,
"recommended_action_keys": ["hello.check_enabled", "hello.run_echo"]
}
],
"fallback_if_no_plugin": [
"Report plugin unavailable",
"Propose install/enable step",
"Avoid unsafe writes without confirmation"
]
}SkillSpec also supports pointer fields in existing skills/*.md YAML frontmatter: skill_spec_path, skillSpecPath, skillspec_path, or spec_path.
Spec Lookup Tools
When spec mode activates, the agent uses these built-in tools to discover and select actions. They are registered under the CLAWMAGIC_SPEC_PACKETING_ENABLED feature flag (default: enabled).
| Tool | Input | Returns |
|---|---|---|
skill.search | text, tags, limit | Matching SkillSpec entries |
skill.get | skill_ids | Full SkillSpec detail for selected skills |
plugin.list | (none) | Compact plugin registry summary |
action.catalog | plugin_ids, text, tags, limit | Action index with keys, descriptions, tags |
action.detail | plugin_id, action_keys | Full action spec with schemas and templates |
action.catalog_from_code | plugin_id, limit | Inferred actions from code inspection |
Agent Execution Flow
When an agent determines it needs to use a plugin, the spec-mode flow is:
- Skill selection (optional): agent calls
skill.searchto find matching SkillSpec, thenskill.getfor full detail. - Plugin selection: agent calls
plugin.listto see available plugins, picks the right one. - Action catalog: agent calls
action.catalogfor the chosen plugin to see available actions. - Action detail: agent calls
action.detailwith selected action keys to get schemas, templates, and risk info. - Execute: agent builds the tool call from
tool_args_templateand executes it. Spec-mode guard verifies the action was loaded viaaction.detailbefore allowing execution. - Verify: agent checks results against
verification_stepsand followsfallbackif needed.
Steps 1-4 are cached as spec packets with stable packet_id values. Repeated lookups reuse cached packets rather than re-injecting full payloads.
Risk Classification
Every action has a danger_level that determines confirmation behavior:
| Level | Confirmation | Examples |
|---|---|---|
read_only | Never required | List files, get status, echo input |
write | Required for inferred actions | Write files, update config, create records |
destructive | Always required | Delete files, drop data, uninstall |
security_sensitive | Always required | Modify permissions, rotate keys, change auth |
For inferred actions (from code inspection, not ActionSpec), write, destructive, and security_sensitive actions all require spec_confirmed=true and spec_confirmation_text in the tool call args.
Fallback Behavior
When a plugin has no actionspec.json, the runtime builds an inferred action catalog using this priority chain:
- actionspec.json — authoritative, used if present
- Runtime describe summary — from
GET /api/plugins/:id/actions - Bounded source scan — inspects plugin source with file/char/depth/time limits
Inferred catalogs are tagged with "confidence": "medium" and include warnings like "actionspec.json missing". The agent can still execute inferred actions, but risky ones require explicit user confirmation.
Spec-Mode Execution Guard
When spec mode is active for a session, the runtime enforces:
- Plugin/tool actions require
action.detailto have been loaded for the target action key. - The
spec_action_keyfield in tool args must match a loaded action. - Fixed fields in
tool_args_templateare validated against actual tool args (template-fidelity guard). - Ambiguous action keys (same key in multiple plugins without
plugin_id) are blocked with disambiguation guidance. - If an action key is invalid, the agent receives “did you mean” suggestions with numbered alternatives.
Spec mode uses an explicit session flag — non-spec calls are never accidentally blocked.
Security Hardening
- Path confinement: ActionSpec paths must resolve within the plugin root. Symlink escape attempts (resolving outside the plugin folder) are rejected.
- Identity binding: the runtime uses the installed plugin’s manifest
id, ignoring anyplugin_idoverride inactionspec.json. - Action-key hygiene: blank or whitespace-only action keys are silently dropped.
- File-size caps: oversized
actionspec.jsonorskill.jsonfiles fall back to code inspection. - Tool binding: CLI-template actions (using
cli_command_template) are bound tolocal_run_commandand block mismatched tool names. - Packet retention: bounded per-session packet count with TTL eviction and startup cleanup via
cleanupSpecPacketStores().
Scaffold a New ActionSpec
Use the built-in scaffold utility to generate actionspec.json and skill.json templates for any installed plugin:
# Scaffold ActionSpec for a plugin npm run spec:scaffold -- --plugin <plugin_id> # Run ActionSpec test suite npm run test:spec-packeting # Feature flag (default: enabled) CLAWMAGIC_SPEC_PACKETING_ENABLED=true
The scaffold generates starter files with correct schema_version values and placeholder actions derived from the plugin manifest. Edit the generated files to add accurate schemas, risk levels, and procedures.
Cross-System Compatibility
ActionSpec is designed for ClawMagic but can improve plugin usage in other claw-family systems:
- ClawMagic: full ActionSpec flow with spec-mode guards, packet caching, and risk-tiered confirmation.
- OpenClaw: can read
actionspec.jsonfor action discovery. Addopenclaw.plugin.jsonalongside for full OpenClaw compatibility. - Other agent systems:
actionspec.jsonis a standard JSON file. Any agent can parse it to understand available actions, input schemas, and risk levels.
The SKILL.md format remains supported for the current plugin ecosystem. skill.json and actionspec.json are additive and optional.
Marketplace Plugin Packaging
When packaging a plugin for the ClawMagic Marketplace, include ActionSpec files alongside your claw.plugin.json manifest:
claw.plugin.json # Required — marketplace manifest actionspec.json # Recommended — action catalog skill.json # Optional — skill routing hints plugin/ src/index.ts # Entry point ...runtime code... docs/ # Optional
Plugins with ActionSpec pass review faster because reviewers can verify action boundaries, risk classifications, and permission scopes directly from the spec.
Telemetry and Diagnostics
Spec packet telemetry writes to a dedicated local diagnostics file at state/diagnostics/spec_packets.jsonl. Events tracked:
packet_upsert— new or replaced packet storedpacket_cache_hit— existing packet reusedaction_detail_loaded— full action detail fetched for executionspec_guard_block— execution blocked by spec-mode guardpacket_cleanup— expired packets evicted