Skip to content

feat: execution plan governance plugin#21648

Closed
nayname wants to merge 1 commit intoopenclaw:mainfrom
ThousandMonkeysTypewriter:main
Closed

feat: execution plan governance plugin#21648
nayname wants to merge 1 commit intoopenclaw:mainfrom
ThousandMonkeysTypewriter:main

Conversation

@nayname
Copy link

@nayname nayname commented Feb 20, 2026

Summary

Introduces a plan-first governance layer making execution explicit and inspectable. Before tools run, an LLM generates a structured execution plan. The plan becomes the single source of truth — nothing happens unless it's in the plan.

Why

Current flow: LLM decides tool → tool executes → you find out after.

Governed flow: LLM generates plan → plan validated → execution bound to plan.

This complements security guardrails #6095: they block dangerous calls, this blocks unplanned calls.

How It Works

  1. before_request hook intercepts user message
  2. LLM generates structured plan (schema-defined JSON)
  3. Plan stored by runId
  4. Plan later validated/constrained/executed (probably without free-form tool calls from LLM) — not present in this PR

Schema

Current simplistic schema:

  • description_for_user — human-readable summary
  • five_w_one_h — who, what, where, when, why, how
  • procedure — ordered steps, no branching
  • surface_effects — what gets touched/modified/created/deleted
  • constraints — hard limits
  • execution_mode — preview or execute

Related

Status

Proof of concept. This PR defines the model and artifact shape — it does not implement enforcement or execution binding. Looking for feedback on whether this direction aligns with governance extensibility post-#6095.

Greptile Summary

This PR introduces a governance layer that generates execution plans before tool execution. However, the implementation has several critical issues that prevent it from working:

  • Uses non-existent hook before_request instead of valid hooks like before_agent_start or before_prompt_build
  • Imports incorrect types from @anthropic/plugin-sdk that don't exist in the actual exports
  • Calls api.completion() method which is not available on the plugin API
  • Accesses runId on hook context where it doesn't exist
  • Empty planning prompt template that would cause plan generation to fail
  • Event structure assumptions that don't match actual hook event types

The concept is solid and aligns with the security extensibility goals, but the code needs significant rework to use the correct OpenClaw plugin APIs and hooks defined in PR #6095.

Confidence Score: 0/5

  • This PR cannot be merged - it contains multiple critical implementation errors that would cause runtime failures
  • The code uses non-existent hooks, imports types that don't exist, calls undefined API methods, and has an empty planning prompt. These are not minor issues but fundamental implementation problems that prevent the code from executing at all. The plugin would fail immediately on load or first invocation.
  • extensions/external-plan-governance/index.ts requires complete rework to use correct OpenClaw plugin APIs and hook system

Last reviewed commit: 404ad20

(2/5) Greptile learns from your feedback when you react with thumbs up/down!

@nayname nayname changed the title External governance feat: execution plan governance plugin Feb 20, 2026
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 files reviewed, 7 comments

Edit Code Review Agent Settings | Greptile

// -------------------------------------------------------------------------
// before_request: Generate execution plan via LLM
// -------------------------------------------------------------------------
api.on("before_request", async (event, ctx: PluginHookContext) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

before_request is not a valid hook in the OpenClaw plugin system. Valid hooks are defined in src/plugins/types.ts:298-318 and do not include before_request. Consider using before_agent_start or before_prompt_build instead.

Suggested change
api.on("before_request", async (event, ctx: PluginHookContext) => {
api.on("before_agent_start", async (event, ctx: PluginHookAgentContext) => {
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 81

Comment:
`before_request` is not a valid hook in the OpenClaw plugin system. Valid hooks are defined in `src/plugins/types.ts:298-318` and do not include `before_request`. Consider using `before_agent_start` or `before_prompt_build` instead.

```suggestion
  api.on("before_agent_start", async (event, ctx: PluginHookAgentContext) => {
```

How can I resolve this? If you propose a fix, please make it concise.

* The plan is the single source of truth.
*/

import type { PluginApi, PluginHookContext, PluginHookToolContext } from "@anthropic/plugin-sdk";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PluginApi, PluginHookContext, and PluginHookToolContext are not exported from @anthropic/plugin-sdk. The correct exports are OpenClawPluginApi, PluginHookAgentContext, etc. from the plugin-sdk index.

Suggested change
import type { PluginApi, PluginHookContext, PluginHookToolContext } from "@anthropic/plugin-sdk";
import type { OpenClawPluginApi, PluginHookAgentContext, PluginHookToolContext } from "@anthropic/plugin-sdk";
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 11

Comment:
`PluginApi`, `PluginHookContext`, and `PluginHookToolContext` are not exported from `@anthropic/plugin-sdk`. The correct exports are `OpenClawPluginApi`, `PluginHookAgentContext`, etc. from the plugin-sdk index.

```suggestion
import type { OpenClawPluginApi, PluginHookAgentContext, PluginHookToolContext } from "@anthropic/plugin-sdk";
```

How can I resolve this? If you propose a fix, please make it concise.

// ============================================================================
// Plugin
// ============================================================================

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function signature should use OpenClawPluginApi instead of PluginApi.

Suggested change
export default function executionPlanGovernance(api: OpenClawPluginApi): void {
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 68

Comment:
Function signature should use `OpenClawPluginApi` instead of `PluginApi`.

```suggestion
export default function executionPlanGovernance(api: OpenClawPluginApi): void {
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +98 to +102
// Note: This uses OpenClaw's internal completion API
const planResponse = await api.completion?.({
messages: [{ role: "user", content: planningPrompt }],
max_tokens: 1024,
temperature: 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api.completion is not a valid method on OpenClawPluginApi. The plugin API doesn't provide a completion method for calling the LLM. You'll need to use a different approach to generate the execution plan.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 98-102

Comment:
`api.completion` is not a valid method on `OpenClawPluginApi`. The plugin API doesn't provide a completion method for calling the LLM. You'll need to use a different approach to generate the execution plan.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +60 to +62

function buildPlanningPrompt(userMessage: string, defaultMode: "preview" | "execute"): string {
return `...`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty prompt template - this function should return the actual prompt that instructs the LLM to generate an execution plan according to the schema. Without this, plan generation will fail.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 60-62

Comment:
Empty prompt template - this function should return the actual prompt that instructs the LLM to generate an execution plan according to the schema. Without this, plan generation will fail.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +82 to +83
const runId = ctx.runId;
if (!runId) return {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

runId is not available on PluginHookAgentContext. The context only includes agentId, sessionKey, sessionId, workspaceDir, and messageProvider according to src/plugins/types.ts:321-327.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 82-83

Comment:
`runId` is not available on `PluginHookAgentContext`. The context only includes `agentId`, `sessionKey`, `sessionId`, `workspaceDir`, and `messageProvider` according to `src/plugins/types.ts:321-327`.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +86 to +89
const messages =
(event as { messages?: Array<{ role: string; content: string }> }).messages ?? [];
const lastUserMessage = messages.filter((m) => m.role === "user").pop();
if (!lastUserMessage) return {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Event structure depends on which hook is used. For before_agent_start, the event has prompt and optional messages fields (see src/plugins/types.ts:355-359). Current code assumes a messages array structure that may not match the actual event type.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/external-plan-governance/index.ts
Line: 86-89

Comment:
Event structure depends on which hook is used. For `before_agent_start`, the event has `prompt` and optional `messages` fields (see `src/plugins/types.ts:355-359`). Current code assumes a `messages` array structure that may not match the actual event type.

How can I resolve this? If you propose a fix, please make it concise.

@openclaw-barnacle
Copy link

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle bot added the stale Marked as stale due to inactivity label Feb 28, 2026
@openclaw-barnacle
Copy link

Please make this as a third-party plugin that you maintain yourself in your own repo. Docs: https://docs.openclaw.ai/plugin. Feel free to open a PR after to add it to our community plugins page: https://docs.openclaw.ai/plugins/community

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

r: third-party-extension size: L stale Marked as stale due to inactivity

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants