diff --git a/docs/plugins/sdk-migration.md b/docs/plugins/sdk-migration.md
index 394c59c3d42..82aab4afcc9 100644
--- a/docs/plugins/sdk-migration.md
+++ b/docs/plugins/sdk-migration.md
@@ -725,18 +725,18 @@ canonical replacement.
-
+
**Old**: `runtime.tasks.flow` (singular) returned a live task-flow accessor.
- **New**: `runtime.tasks.flows` (plural) returns DTO-based TaskFlow access,
- which is import-safe and does not require the full task runtime to be
- loaded.
+ **New**: `runtime.tasks.managedFlows` keeps the managed TaskFlow mutation
+ runtime for plugins that create, update, cancel, or run child tasks from a
+ flow. Use `runtime.tasks.flows` when the plugin only needs DTO-based reads.
```typescript
// Before
- const flow = api.runtime.tasks.flow(ctx);
+ const flow = api.runtime.tasks.flow.fromToolContext(ctx);
// After
- const flows = api.runtime.tasks.flows(ctx);
+ const flow = api.runtime.tasks.managedFlows.fromToolContext(ctx);
```
diff --git a/docs/plugins/sdk-runtime.md b/docs/plugins/sdk-runtime.md
index 20a3ee0650a..63cc530c34e 100644
--- a/docs/plugins/sdk-runtime.md
+++ b/docs/plugins/sdk-runtime.md
@@ -179,11 +179,11 @@ Internal OpenClaw runtime code has the same direction: load config once at the C
Inside the Gateway this runtime is in-process. In plugin CLI commands it calls the configured Gateway over RPC, so commands such as `openclaw googlemeet recover-tab` can inspect paired nodes from the terminal. Node commands still go through normal Gateway node pairing, command allowlists, and node-local command handling.
-
+
Bind a Task Flow runtime to an existing OpenClaw session key or trusted tool context, then create and manage Task Flows without passing an owner on every call.
```typescript
- const taskFlow = api.runtime.taskFlow.fromToolContext(ctx);
+ const taskFlow = api.runtime.tasks.managedFlows.fromToolContext(ctx);
const created = taskFlow.createManaged({
controllerId: "my-plugin/review-batch",
diff --git a/docs/plugins/webhooks.md b/docs/plugins/webhooks.md
index 3be601ac0e6..52b1dfc836c 100644
--- a/docs/plugins/webhooks.md
+++ b/docs/plugins/webhooks.md
@@ -89,7 +89,7 @@ The plugin applies:
- Request body size and timeout guards
- Fixed-window rate limiting
- In-flight request limiting
-- Owner-bound TaskFlow access through `api.runtime.taskFlow.bindSession(...)`
+- Owner-bound TaskFlow access through `api.runtime.tasks.managedFlows.bindSession(...)`
## Request format
diff --git a/extensions/lobster/index.ts b/extensions/lobster/index.ts
index 5163fad561d..901b9c7c546 100644
--- a/extensions/lobster/index.ts
+++ b/extensions/lobster/index.ts
@@ -13,8 +13,8 @@ export default definePluginEntry({
return null;
}
const taskFlow =
- api.runtime?.taskFlow && ctx.sessionKey
- ? api.runtime.taskFlow.fromToolContext(ctx)
+ api.runtime?.tasks.managedFlows && ctx.sessionKey
+ ? api.runtime.tasks.managedFlows.fromToolContext(ctx)
: undefined;
return createLobsterTool(api, { taskFlow }) as AnyAgentTool;
}) as OpenClawPluginToolFactory,
diff --git a/extensions/lobster/src/lobster-taskflow.ts b/extensions/lobster/src/lobster-taskflow.ts
index a46e6be5f42..8ca2c92b1d8 100644
--- a/extensions/lobster/src/lobster-taskflow.ts
+++ b/extensions/lobster/src/lobster-taskflow.ts
@@ -12,7 +12,7 @@ type JsonLike =
};
type BoundTaskFlow = ReturnType<
- NonNullable["taskFlow"]["bindSession"]
+ NonNullable["tasks"]["managedFlows"]["bindSession"]
>;
type FlowRecord = ReturnType;
diff --git a/extensions/lobster/src/lobster-tool.ts b/extensions/lobster/src/lobster-tool.ts
index f2d1b06eabe..d9ed36d6db2 100644
--- a/extensions/lobster/src/lobster-tool.ts
+++ b/extensions/lobster/src/lobster-tool.ts
@@ -13,7 +13,7 @@ import {
} from "./lobster-taskflow.js";
type BoundTaskFlow = ReturnType<
- NonNullable["taskFlow"]["bindSession"]
+ NonNullable["tasks"]["managedFlows"]["bindSession"]
>;
type JsonLike =
diff --git a/extensions/lobster/src/taskflow-test-helpers.ts b/extensions/lobster/src/taskflow-test-helpers.ts
index 8e2f89abc50..4845663d466 100644
--- a/extensions/lobster/src/taskflow-test-helpers.ts
+++ b/extensions/lobster/src/taskflow-test-helpers.ts
@@ -2,7 +2,7 @@ import { vi } from "vitest";
import type { OpenClawPluginApi } from "../runtime-api.js";
export type BoundTaskFlow = ReturnType<
- NonNullable["taskFlow"]["bindSession"]
+ NonNullable["tasks"]["managedFlows"]["bindSession"]
>;
export function createFakeTaskFlow(overrides?: Partial): BoundTaskFlow {
diff --git a/extensions/webhooks/index.test.ts b/extensions/webhooks/index.test.ts
index 65be0461a8c..b984d48ff5b 100644
--- a/extensions/webhooks/index.test.ts
+++ b/extensions/webhooks/index.test.ts
@@ -14,8 +14,10 @@ function createApi(params?: {
source: "test",
pluginConfig: params?.pluginConfig ?? {},
runtime: {
- taskFlow: {
- bindSession: vi.fn(({ sessionKey }: { sessionKey: string }) => ({ sessionKey })),
+ tasks: {
+ managedFlows: {
+ bindSession: vi.fn(({ sessionKey }: { sessionKey: string }) => ({ sessionKey })),
+ },
},
} as unknown as OpenClawPluginApi["runtime"],
registerHttpRoute: params?.registerHttpRoute ?? vi.fn(),
diff --git a/extensions/webhooks/index.ts b/extensions/webhooks/index.ts
index abcc6c43112..a3cc509d562 100644
--- a/extensions/webhooks/index.ts
+++ b/extensions/webhooks/index.ts
@@ -17,7 +17,7 @@ function registerWebhookRoutes(api: OpenClawPluginApi): void {
});
for (const route of routes) {
- const taskFlow = api.runtime.taskFlow.bindSession({
+ const taskFlow = api.runtime.tasks.managedFlows.bindSession({
sessionKey: route.sessionKey,
});
const target: TaskFlowWebhookTarget = {
diff --git a/extensions/webhooks/src/http.ts b/extensions/webhooks/src/http.ts
index 349c2514aca..5f2d136cae5 100644
--- a/extensions/webhooks/src/http.ts
+++ b/extensions/webhooks/src/http.ts
@@ -18,7 +18,7 @@ import {
} from "../runtime-api.js";
import type { WebhookSecretInput } from "./config.js";
-type BoundTaskFlowRuntime = ReturnType;
+type BoundTaskFlowRuntime = ReturnType;
type JsonValue = null | boolean | number | string | JsonValue[] | { [key: string]: JsonValue };
diff --git a/src/plugin-sdk/test-helpers/plugin-runtime-mock.ts b/src/plugin-sdk/test-helpers/plugin-runtime-mock.ts
index 636486eccc4..f1ba68c2a45 100644
--- a/src/plugin-sdk/test-helpers/plugin-runtime-mock.ts
+++ b/src/plugin-sdk/test-helpers/plugin-runtime-mock.ts
@@ -73,10 +73,10 @@ export function createPluginRuntimeMock(overrides: DeepPartial =
const taskFlow = {
bindSession: vi.fn(
createTaskFlowSessionMock,
- ) as unknown as PluginRuntime["taskFlow"]["bindSession"],
+ ) as unknown as PluginRuntime["tasks"]["managedFlows"]["bindSession"],
fromToolContext: vi.fn(
createTaskFlowSessionMock,
- ) as unknown as PluginRuntime["taskFlow"]["fromToolContext"],
+ ) as unknown as PluginRuntime["tasks"]["managedFlows"]["fromToolContext"],
};
const base: PluginRuntime = {
version: "1.0.0-test",
@@ -468,6 +468,7 @@ export function createPluginRuntimeMock(overrides: DeepPartial =
bindSession: vi.fn(),
fromToolContext: vi.fn(),
} as PluginRuntime["tasks"]["flows"],
+ managedFlows: taskFlow,
flow: taskFlow,
},
taskFlow,
diff --git a/src/plugins/compat/registry.ts b/src/plugins/compat/registry.ts
index 03a577076ca..54e085be411 100644
--- a/src/plugins/compat/registry.ts
+++ b/src/plugins/compat/registry.ts
@@ -720,7 +720,8 @@ export const PLUGIN_COMPAT_RECORDS = [
deprecated: "2026-04-26",
warningStarts: "2026-04-26",
removeAfter: "2026-07-26",
- replacement: "`api.runtime.tasks.flows`",
+ replacement:
+ "`api.runtime.tasks.managedFlows` for managed mutations or `api.runtime.tasks.flows` for DTO reads",
docsPath: "/plugins/sdk-runtime",
surfaces: ["api.runtime.taskFlow", "api.runtime.tasks.flow"],
diagnostics: ["plugin runtime compatibility warning"],
diff --git a/src/plugins/runtime/index.test.ts b/src/plugins/runtime/index.test.ts
index 40e335ae3ec..ae1dcaa5ce9 100644
--- a/src/plugins/runtime/index.test.ts
+++ b/src/plugins/runtime/index.test.ts
@@ -191,7 +191,7 @@ describe("plugin runtime command execution", () => {
},
},
{
- name: "exposes canonical runtime.tasks.runs and runtime.tasks.flows while keeping legacy TaskFlow aliases",
+ name: "exposes canonical runtime.tasks task runtimes while keeping legacy TaskFlow aliases",
assert: (runtime: ReturnType) => {
expectFunctionKeys(runtime.tasks.runs as Record, [
"bindSession",
@@ -201,11 +201,16 @@ describe("plugin runtime command execution", () => {
"bindSession",
"fromToolContext",
]);
+ expectFunctionKeys(runtime.tasks.managedFlows as Record, [
+ "bindSession",
+ "fromToolContext",
+ ]);
expectFunctionKeys(runtime.tasks.flow as Record, [
"bindSession",
"fromToolContext",
]);
- expect(runtime.taskFlow).toBe(runtime.tasks.flow);
+ expect(runtime.tasks.managedFlows).toBe(runtime.tasks.flow);
+ expect(runtime.taskFlow).toBe(runtime.tasks.managedFlows);
},
},
{
diff --git a/src/plugins/runtime/runtime-tasks.ts b/src/plugins/runtime/runtime-tasks.ts
index 9406a218305..fed143ee07d 100644
--- a/src/plugins/runtime/runtime-tasks.ts
+++ b/src/plugins/runtime/runtime-tasks.ts
@@ -217,6 +217,7 @@ export function createRuntimeTasks(params: {
return {
runs: createRuntimeTaskRuns(),
flows: createRuntimeTaskFlows(),
+ managedFlows: params.legacyTaskFlow,
flow: params.legacyTaskFlow,
};
}
diff --git a/src/plugins/runtime/runtime-tasks.types.ts b/src/plugins/runtime/runtime-tasks.types.ts
index 28f7db24fe3..6de41ac08c1 100644
--- a/src/plugins/runtime/runtime-tasks.types.ts
+++ b/src/plugins/runtime/runtime-tasks.types.ts
@@ -64,6 +64,7 @@ export type PluginRuntimeTaskFlows = {
export type PluginRuntimeTasks = {
runs: PluginRuntimeTaskRuns;
flows: PluginRuntimeTaskFlows;
+ managedFlows: PluginRuntimeTaskFlow;
/** @deprecated Use runtime.tasks.flows for DTO-based TaskFlow access. */
flow: PluginRuntimeTaskFlow;
};
diff --git a/src/plugins/runtime/types-core.ts b/src/plugins/runtime/types-core.ts
index 96d428f2106..3c75c02ed7d 100644
--- a/src/plugins/runtime/types-core.ts
+++ b/src/plugins/runtime/types-core.ts
@@ -231,6 +231,7 @@ export type PluginRuntimeCore = {
tasks: {
runs: PluginRuntimeTaskRuns;
flows: PluginRuntimeTaskFlows;
+ managedFlows: import("./runtime-taskflow.types.js").PluginRuntimeTaskFlow;
/** @deprecated Use runtime.tasks.flows for DTO-based TaskFlow access. */
flow: import("./runtime-taskflow.types.js").PluginRuntimeTaskFlow;
};