Plugin Actions
Understand command, api, execute, execution context, and cooperative timeouts in plugin actions
Plugin Actions
Plugin actions are the most direct explicit capability surface of a plugin.
An action is mainly built from:
allowWhenDisabledcommandapiexecute
The core layer is execute
Minimal example:
actions: {
status: {
execute: async ({ context }) => {
return {
success: true,
data: {
workspace_path: context.workspace_path,
},
};
},
},
}execute is responsible for:
- receiving structured payload
- running the business logic
- returning
success / data / error / message
Every Action call receives two separate readonly inputs:
context: stable Agent and Workspace capabilities such as identity, files, Shell, logger, web services, sessions, and pluginsexecution: per-call identity, cancellation, optional Session scope, and the effective Step snapshot
execution.call_id matches the Tool Call ID for model tools. execution.session contains session_id, turn_id, and optional interactions for Session calls. execution.snapshot contains effective workspace_env and agent_systems. Direct CLI, HTTP, and scheduler calls receive a runtime-generated call_id and cancellation signal without a Session scope. Pass execution.abort_signal to network requests, polling, and other long-running operations.
command
command handles CLI-side mapping.
It is a good place to define:
- help text
- commander arguments and options
- how CLI input becomes structured payload
api
api handles HTTP-side input mapping.
It is a good place to define:
- method
- path
- how an HTTP request becomes structured payload
timeout_ms
An Action may declare a cooperative timeout:
actions: {
search: {
timeout_ms: 30_000,
execute: async ({ execution }) => {
const response = await fetch("https://example.com", {
signal: execution.abort_signal,
});
return { success: true, data: { status: response.status } };
},
},
}The timeout aborts execution.abort_signal. This is cooperative: the Action must pass the signal to the underlying operation. A business failure does not change the Plugin lifecycle state.
allowWhenDisabled
This is one of the easiest plugin-specific details to miss.
It means:
- this action is still allowed even if the plugin is currently disabled
Typical cases:
statusinstallconfiguremodels
In other words, the actions you often need precisely because the plugin is not yet fully usable.
Without allowWhenDisabled: true, normal actions on a disabled plugin are blocked.
What context does execute receive
Plugin Actions deliberately separate stable capabilities from per-call state. Read Agent and Workspace services from context; read call identity, cancellation, Session interaction, and the effective Step snapshot from execution. Product configuration is passed by the upstream host when constructing the Plugin instance.
A slightly fuller example
actions: {
use: {
allowWhenDisabled: true,
command: {
description: "switch the default provider",
mapInput({ args }) {
return {
provider: String(args[0] || ""),
};
},
},
execute: async ({ input }) => {
const provider = String((input as { provider?: unknown }).provider || "").trim();
if (!provider) {
return {
success: false,
error: "provider is required",
message: "provider is required",
};
}
return {
success: true,
data: { provider },
};
},
},
}